Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b385a17b1 | |||
| 8cca01851a | |||
| 478417bb56 | |||
| 739202fddf | |||
| 8593941005 | |||
| b2852f5d57 | |||
| 6c059e351f | |||
| e86911ed2a | |||
| 17cc3b8297 | |||
| 43016df241 | |||
| ba4eb3ce7d | |||
| ba7dd3cd89 | |||
| 5e37b7f5ca | |||
| 84eaf8f3cb | |||
| c090824c93 | |||
| add7f56117 | |||
| 676f38d22c | |||
| bc82f2fa68 | |||
| 995cf902fb | |||
| 87152ecc71 | |||
| dbc0478e40 | |||
| 9eb1db9034 | |||
| 4820088457 | |||
| fcd0444c57 | |||
| 067e69f339 | |||
| 015939b150 | |||
| eb8cf62d74 | |||
| 308b9913e7 | |||
| 6b621ce6f7 | |||
| 42d0203b49 | |||
| c591a1470a | |||
| eb08046e94 | |||
| 2ff37da5f5 | |||
| ee99afc3a3 | |||
| 34017a26a3 | |||
| 29f58a5840 | |||
| d2d78a7299 | |||
| 6e66ee7c35 | |||
| 4bda800e11 | |||
| 2cce9776be | |||
| 20b13ad0c0 | |||
| 08ac52ca53 | |||
| 9c220cd359 | |||
| ab443d1638 | |||
| 186aede95c | |||
| db52fa94e7 | |||
| ee18e1a499 | |||
| 9cf4bf2263 | |||
| 36350f3c5c | |||
| f3476c68ff | |||
| 8fd8f1c831 | |||
| 7d2066693b | |||
| 6b01b878cb | |||
| 2e32eb704f | |||
| b81b144680 | |||
| 256e41a505 | |||
| 3054364101 | |||
| 40b8802874 | |||
| 49f53fceaf | |||
| 291c12a54c | |||
| 2b3413fad4 | |||
| 3eab530e95 | |||
| 7d35be4f89 | |||
| 800c2e9c71 | |||
| edf8174581 | |||
| 8ae67204eb | |||
| 5f2540e556 | |||
| 776e3f26ef | |||
| 46f4ac1f33 | |||
| 73d22552e6 | |||
| 650419c952 | |||
| 1e8adde480 | |||
| a9e1242aef | |||
| a222edee5a | |||
| 7a12897be4 | |||
| 7fa8081032 | |||
| 212bf981f7 |
@@ -25,7 +25,12 @@ extends:
|
||||
stages:
|
||||
- stage: Stage
|
||||
jobs:
|
||||
- job: HostJob
|
||||
- job: Build
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
path: $(Build.ArtifactStagingDirectory)/esrp-build
|
||||
artifact: esrp-build
|
||||
steps:
|
||||
- bash: |
|
||||
if [[ ! "$CURRENT_BRANCH" =~ ^release-.* ]]; then
|
||||
@@ -50,28 +55,39 @@ extends:
|
||||
- bash: ./scripts/download_driver.sh
|
||||
displayName: 'Download driver'
|
||||
|
||||
- bash: mvn -B deploy -D skipTests --no-transfer-progress --activate-profiles release -D gpg.passphrase=$GPG_PASSPHRASE -DaltDeploymentRepository=snapshot-repo::default::file:$(pwd)/local-build
|
||||
- bash: mvn -B deploy -D skipTests --no-transfer-progress --activate-profiles release -D gpg.passphrase=$GPG_PASSPHRASE -DaltDeploymentRepository=snapshot-repo::default::file:$(Build.ArtifactStagingDirectory)/esrp-build
|
||||
displayName: 'Build and deploy to a local directory'
|
||||
env:
|
||||
GPG_PASSPHRASE: $(GPG_PASSPHRASE) # secret variable has to be mapped to an env variable
|
||||
|
||||
- task: EsrpRelease@7
|
||||
|
||||
- job: Publish
|
||||
dependsOn: Build
|
||||
templateContext:
|
||||
type: releaseJob
|
||||
isProduction: true
|
||||
inputs:
|
||||
connectedservicename: 'Playwright-ESRP-Azure'
|
||||
keyvaultname: 'pw-publishing-secrets'
|
||||
authcertname: 'ESRP-Release-Auth'
|
||||
signcertname: 'ESRP-Release-Sign'
|
||||
clientid: '13434a40-7de4-4c23-81a3-d843dc81c2c5'
|
||||
intent: 'PackageDistribution'
|
||||
contenttype: 'Maven'
|
||||
# Keeping it commented out as a workaround for:
|
||||
# https://portal.microsofticm.com/imp/v3/incidents/incident/499972482/summary
|
||||
# contentsource: 'folder'
|
||||
folderlocation: './local-build'
|
||||
waitforreleasecompletion: true
|
||||
owners: 'yurys@microsoft.com'
|
||||
approvers: 'maxschmitt@microsoft.com'
|
||||
serviceendpointurl: 'https://api.esrp.microsoft.com'
|
||||
mainpublisher: 'Playwright'
|
||||
domaintenantid: '72f988bf-86f1-41af-91ab-2d7cd011db47'
|
||||
displayName: 'ESRP Release to Maven'
|
||||
- input: pipelineArtifact
|
||||
artifactName: esrp-build
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/esrp-build
|
||||
steps:
|
||||
- checkout: none
|
||||
- task: EsrpRelease@9
|
||||
inputs:
|
||||
connectedservicename: 'Playwright-ESRP-PME'
|
||||
usemanagedidentity: true
|
||||
keyvaultname: 'playwright-esrp-pme'
|
||||
signcertname: 'ESRP-Release-Sign'
|
||||
clientid: '13434a40-7de4-4c23-81a3-d843dc81c2c5'
|
||||
intent: 'PackageDistribution'
|
||||
contenttype: 'Maven'
|
||||
# Keeping it commented out as a workaround for:
|
||||
# https://portal.microsofticm.com/imp/v3/incidents/incident/499972482/summary
|
||||
# contentsource: 'folder'
|
||||
folderlocation: '$(Build.ArtifactStagingDirectory)/esrp-build'
|
||||
waitforreleasecompletion: true
|
||||
owners: 'yurys@microsoft.com'
|
||||
approvers: 'maxschmitt@microsoft.com'
|
||||
serviceendpointurl: 'https://api.esrp.microsoft.com'
|
||||
mainpublisher: 'Playwright'
|
||||
domaintenantid: '975f013f-7f24-47e8-a7d3-abc4752bf346'
|
||||
displayName: 'ESRP Release to Maven'
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/java
|
||||
{
|
||||
"name": "Java",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/java:1-21-bookworm",
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/java:1": {
|
||||
"version": "none",
|
||||
"installGradle": "false",
|
||||
"installMaven": "true"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
||||
}
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "java -version",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
+18
-1
@@ -3,8 +3,25 @@ updates:
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/" # Location of the pom.xml file
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
# Create a group of dependencies to be updated together in one pull request
|
||||
all:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
allow:
|
||||
- dependency-type: "direct" # Optional: Only update direct dependencies
|
||||
- dependency-type: "indirect" # Optional: Only update indirect (transitive) dependencies
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
@@ -3,11 +3,6 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
is_release:
|
||||
required: true
|
||||
type: boolean
|
||||
description: "Is this a release image?"
|
||||
jobs:
|
||||
publish-canary-docker:
|
||||
name: publish to DockerHub
|
||||
@@ -33,6 +28,3 @@ jobs:
|
||||
platforms: arm64
|
||||
- uses: actions/checkout@v4
|
||||
- run: ./utils/docker/publish_docker.sh stable
|
||||
if: (github.event_name != 'workflow_dispatch' && !github.event.release.prerelease) || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_release == 'true')
|
||||
- run: ./utils/docker/publish_docker.sh canary
|
||||
if: (github.event_name != 'workflow_dispatch' && github.event.release.prerelease) || (github.event_name == 'workflow_dispatch' && github.event.inputs.is_release != 'true')
|
||||
|
||||
+18
-13
@@ -8,6 +8,8 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
env:
|
||||
PW_MAX_RETRIES: 3
|
||||
jobs:
|
||||
dev:
|
||||
timeout-minutes: 30
|
||||
@@ -18,10 +20,9 @@ jobs:
|
||||
browser: [chromium, firefox, webkit]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: 8
|
||||
@@ -30,6 +31,8 @@ jobs:
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
env:
|
||||
@@ -62,14 +65,13 @@ jobs:
|
||||
browser-channel: msedge
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v2
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: 8
|
||||
@@ -78,17 +80,19 @@ jobs:
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Install MS Edge
|
||||
if: matrix.browser-channel == 'msedge' && matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install msedge" -f playwright/pom.xml
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install msedge" -f playwright/pom.xml
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
env:
|
||||
BROWSER: chromium
|
||||
BROWSER_CHANNEL: ${{ matrix.browser-channel }}
|
||||
|
||||
Java_17:
|
||||
Java_21:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -96,18 +100,19 @@ jobs:
|
||||
browser: [chromium, firefox, webkit]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: adopt
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end
|
||||
env:
|
||||
|
||||
@@ -13,9 +13,9 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
@@ -24,9 +24,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [focal, jammy]
|
||||
flavor: [jammy, noble]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build Docker image
|
||||
run: bash utils/docker/build.sh --amd64 ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
|
||||
- name: Test
|
||||
|
||||
@@ -9,13 +9,19 @@ on:
|
||||
jobs:
|
||||
trigger:
|
||||
name: "trigger"
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.PLAYWRIGHT_APP_ID }}
|
||||
private-key: ${{ secrets.PLAYWRIGHT_PRIVATE_KEY }}
|
||||
repositories: playwright-browsers
|
||||
- run: |
|
||||
curl -X POST \
|
||||
curl -X POST --fail \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${GH_TOKEN}" \
|
||||
--data "{\"event_type\": \"playwright_tests_java\", \"client_payload\": {\"ref\": \"${GITHUB_SHA}\"}}" \
|
||||
https://api.github.com/repos/microsoft/playwright-browsers/dispatches
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }}
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
@@ -19,12 +19,15 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download drivers
|
||||
run: scripts/download_driver.sh
|
||||
- name: Regenerate APIs
|
||||
run: scripts/generate_api.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Update browser versions in README
|
||||
run: scripts/update_readme.sh
|
||||
- name: Verify API is up to date
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
[](https://javadoc.io/doc/com.microsoft.playwright/playwright)
|
||||
[](https://search.maven.org/search?q=com.microsoft.playwright)
|
||||
[](https://oss.sonatype.org/content/repositories/snapshots/com/microsoft/playwright/playwright/)
|
||||
[](https://aka.ms/playwright-slack)
|
||||
[](https://aka.ms/playwright/discord)
|
||||
|
||||
#### [Website](https://playwright.dev/java/) | [API reference](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html)
|
||||
|
||||
@@ -11,59 +10,19 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->127.0.6533.17<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->127.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->136.0.7103.25<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->18.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->137.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/java/docs/intro#system-requirements) for details.
|
||||
## Documentation
|
||||
|
||||
* [Usage](#usage)
|
||||
- [Add Maven dependency](#add-maven-dependency)
|
||||
- [Is Playwright thread-safe?](#is-playwright-thread-safe)
|
||||
* [Examples](#examples)
|
||||
- [Page screenshot](#page-screenshot)
|
||||
- [Mobile and geolocation](#mobile-and-geolocation)
|
||||
- [Evaluate JavaScript in browser](#evaluate-javascript-in-browser)
|
||||
- [Intercept network requests](#intercept-network-requests)
|
||||
* [Documentation](#documentation)
|
||||
* [Contributing](#contributing)
|
||||
* [Is Playwright for Java ready?](#is-playwright-for-java-ready)
|
||||
[https://playwright.dev/java/docs/intro](https://playwright.dev/java/docs/intro)
|
||||
|
||||
## Usage
|
||||
## API Reference
|
||||
|
||||
Playwright requires **Java 8** or newer.
|
||||
[https://playwright.dev/java/docs/api/class-playwright](https://playwright.dev/java/docs/api/class-playwright)
|
||||
|
||||
#### 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 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:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>1.41.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
To run Playwright using Gradle add following dependency to your build.gradle file:
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.41.0'
|
||||
}
|
||||
```
|
||||
|
||||
#### 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 multiple Playwright instances each on its own thread.
|
||||
|
||||
## Examples
|
||||
|
||||
You can find Maven project with the examples [here](./examples).
|
||||
|
||||
#### Page screenshot
|
||||
## Example
|
||||
|
||||
This code snippet navigates to Playwright homepage in Chromium, Firefox and WebKit, and saves 3 screenshots.
|
||||
|
||||
@@ -95,100 +54,9 @@ public class PageScreenshot {
|
||||
}
|
||||
```
|
||||
|
||||
#### Mobile and geolocation
|
||||
## Other languages
|
||||
|
||||
This snippet emulates Mobile Chromium on a device at a given geolocation, navigates to openstreetmap.org, performs action and takes a screenshot.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.options.*;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class MobileAndGeolocation {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.chromium().launch();
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36")
|
||||
.setViewportSize(411, 731)
|
||||
.setDeviceScaleFactor(2.625)
|
||||
.setIsMobile(true)
|
||||
.setHasTouch(true)
|
||||
.setLocale("en-US")
|
||||
.setGeolocation(41.889938, 12.492507)
|
||||
.setPermissions(asList("geolocation")));
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.openstreetmap.org/");
|
||||
page.click("a[data-bs-original-title=\"Show My Location\"]");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("colosseum-pixel2.png")));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Evaluate JavaScript in browser
|
||||
|
||||
This code snippet navigates to example.com in Firefox, and executes a script in the page context.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class EvaluateInBrowserContext {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.firefox().launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.example.com/");
|
||||
Object dimensions = page.evaluate("() => {\n" +
|
||||
" return {\n" +
|
||||
" width: document.documentElement.clientWidth,\n" +
|
||||
" height: document.documentElement.clientHeight,\n" +
|
||||
" deviceScaleFactor: window.devicePixelRatio\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
System.out.println(dimensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Intercept network requests
|
||||
|
||||
This code snippet sets up request routing for a WebKit page to log all network requests.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class InterceptNetworkRequests {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.webkit().launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.route("**", route -> {
|
||||
System.out.println(route.request().url());
|
||||
route.resume();
|
||||
});
|
||||
page.navigate("http://todomvc.com");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Check out our official [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
|
||||
|
||||
Follow [the instructions](https://github.com/microsoft/playwright-java/blob/main/CONTRIBUTING.md#getting-code) to build the project from source and install the driver.
|
||||
|
||||
## Is Playwright for Java ready?
|
||||
|
||||
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.
|
||||
More comfortable in another programming language? [Playwright](https://playwright.dev) is also available in
|
||||
- [Node.js (JavaScript / TypeScript)](https://playwright.dev/docs/intro),
|
||||
- [Python](https://playwright.dev/python/docs/intro).
|
||||
- [.NET](https://playwright.dev/dotnet/docs/intro),
|
||||
|
||||
+2
-3
@@ -2,11 +2,10 @@
|
||||
|
||||
* make sure to have at least Java 8 and Maven 3.6.3
|
||||
* clone playwright for java: http://github.com/microsoft/playwright-java
|
||||
* set new driver version in `scripts/DRIVER_VERSION`
|
||||
* regenerate API: `./scripts/download_driver.sh -f && ./scripts/generate_api.sh && ./scripts/update_readme.sh`
|
||||
* `./scripts/roll_driver.sh 1.47.0-beta-1726138322000`
|
||||
* commit & send PR with the roll
|
||||
|
||||
### Finding driver version
|
||||
## Finding driver version
|
||||
|
||||
For development versions of Playwright, you can find the latest version by looking at [publish_canary](https://github.com/microsoft/playwright/actions/workflows/publish_canary.yml) workflow -> `publish canary NPM & Publish canary Docker` -> `build & publish driver` step -> `PACKAGE_VERSION`
|
||||
<img width="960" alt="image" src="https://github.com/microsoft/playwright-java/assets/9798949/4f33a7f1-b39a-4179-8ae7-fb1d84094c75">
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub issues to track bugs and feature requests. Please search the [existing issues][gh-issues] before filing new ones to avoid duplicates. For new issues, file your bug or feature request as a new issue using corresponding template.
|
||||
|
||||
For help and questions about using this project, please see the [docs site for Playwright for Java][docs].
|
||||
|
||||
Join our community [Discord Server][discord-server] to connect with other developers using Playwright and ask questions in our 'help-playwright' forum.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for Playwright for Java is limited to the resources listed above.
|
||||
|
||||
[gh-issues]: https://github.com/microsoft/playwright-java/issues/
|
||||
[docs]: https://playwright.dev/java/
|
||||
[discord-server]: https://aka.ms/playwright/discord
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.45.1</version>
|
||||
<version>1.52.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
|
||||
@@ -74,7 +74,7 @@ public class DriverJar extends Driver {
|
||||
skip = System.getenv(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
|
||||
}
|
||||
if (skip != null && !"0".equals(skip) && !"false".equals(skip)) {
|
||||
System.out.println("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
|
||||
logMessage("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
|
||||
return;
|
||||
}
|
||||
if (env.get(SELENIUM_REMOTE_URL) != null || System.getenv(SELENIUM_REMOTE_URL) != null) {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.45.1</version>
|
||||
<version>1.52.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
|
||||
+3
-2
@@ -6,16 +6,17 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.45.1</version>
|
||||
<version>1.52.0</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<playwright.version>1.51.0</playwright.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>1.41.0</version>
|
||||
<version>${playwright.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
+14
-1
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.45.1</version>
|
||||
<version>1.52.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
@@ -57,10 +57,23 @@
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
The following slf4j-simple dependency resolves the warning:
|
||||
'SLF4J(W): No SLF4J providers were found.'
|
||||
This warning is produced by the org.java-websocket library.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opentest4j</groupId>
|
||||
<artifactId>opentest4j</artifactId>
|
||||
|
||||
@@ -41,10 +41,28 @@ public interface APIRequest {
|
||||
* </ul>
|
||||
*/
|
||||
public String baseURL;
|
||||
/**
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public List<ClientCertificate> clientCertificates;
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
*/
|
||||
public Map<String, String> extraHTTPHeaders;
|
||||
/**
|
||||
* Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes.
|
||||
*/
|
||||
public Boolean failOnStatusCode;
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
@@ -54,6 +72,12 @@ public interface APIRequest {
|
||||
* Whether to ignore HTTPS errors when sending network requests. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean ignoreHTTPSErrors;
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects. This can be overwritten for each request
|
||||
* individually.
|
||||
*/
|
||||
public Integer maxRedirects;
|
||||
/**
|
||||
* Network proxy settings.
|
||||
*/
|
||||
@@ -100,6 +124,23 @@ public interface APIRequest {
|
||||
this.baseURL = baseURL;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public NewContextOptions setClientCertificates(List<ClientCertificate> clientCertificates) {
|
||||
this.clientCertificates = clientCertificates;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
*/
|
||||
@@ -107,6 +148,13 @@ public interface APIRequest {
|
||||
this.extraHTTPHeaders = extraHTTPHeaders;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes.
|
||||
*/
|
||||
public NewContextOptions setFailOnStatusCode(boolean failOnStatusCode) {
|
||||
this.failOnStatusCode = failOnStatusCode;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
@@ -129,6 +177,15 @@ public interface APIRequest {
|
||||
this.ignoreHTTPSErrors = ignoreHTTPSErrors;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects. This can be overwritten for each request
|
||||
* individually.
|
||||
*/
|
||||
public NewContextOptions setMaxRedirects(int maxRedirects) {
|
||||
this.maxRedirects = maxRedirects;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Network proxy settings.
|
||||
*/
|
||||
|
||||
@@ -58,12 +58,23 @@ public interface APIRequestContext {
|
||||
}
|
||||
}
|
||||
class StorageStateOptions {
|
||||
/**
|
||||
* Set to {@code true} to include IndexedDB in the storage state snapshot.
|
||||
*/
|
||||
public Boolean indexedDB;
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
*/
|
||||
public Path path;
|
||||
|
||||
/**
|
||||
* Set to {@code true} to include IndexedDB in the storage state snapshot.
|
||||
*/
|
||||
public StorageStateOptions setIndexedDB(boolean indexedDB) {
|
||||
this.indexedDB = indexedDB;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
@@ -129,8 +140,7 @@ public interface APIRequestContext {
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
@@ -167,8 +177,7 @@ public interface APIRequestContext {
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
@@ -204,8 +213,7 @@ public interface APIRequestContext {
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
@@ -242,8 +250,7 @@ public interface APIRequestContext {
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
|
||||
@@ -43,8 +43,8 @@ public interface APIResponse {
|
||||
*/
|
||||
Map<String, String> headers();
|
||||
/**
|
||||
* An array with all the request HTTP headers associated with this response. Header names are not lower-cased. Headers with
|
||||
* multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
|
||||
* An array with all the response HTTP headers associated with this response. Header names are not lower-cased. Headers
|
||||
* with multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
|
||||
@@ -29,15 +29,15 @@ import java.util.regex.Pattern;
|
||||
* import com.microsoft.playwright.*;
|
||||
*
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType firefox = playwright.firefox()
|
||||
* Browser browser = firefox.launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate('https://example.com');
|
||||
* browser.close();
|
||||
* }
|
||||
* }
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType firefox = playwright.firefox();
|
||||
* Browser browser = firefox.launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://example.com");
|
||||
* browser.close();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -97,11 +97,33 @@ 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 com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public List<ClientCertificate> clientCertificates;
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public Optional<Contrast> contrast;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -163,10 +185,6 @@ public interface Browser extends AutoCloseable {
|
||||
public List<String> permissions;
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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;
|
||||
/**
|
||||
@@ -296,14 +314,42 @@ public interface Browser extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public NewContextOptions setClientCertificates(List<ClientCertificate> clientCertificates) {
|
||||
this.clientCertificates = clientCertificates;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public NewContextOptions setColorScheme(ColorScheme colorScheme) {
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public NewContextOptions setContrast(Contrast contrast) {
|
||||
this.contrast = Optional.ofNullable(contrast);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -411,20 +457,12 @@ public interface Browser extends AutoCloseable {
|
||||
}
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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 NewContextOptions setProxy(String server) {
|
||||
return setProxy(new Proxy(server));
|
||||
}
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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 NewContextOptions setProxy(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
@@ -627,11 +665,33 @@ 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 com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public List<ClientCertificate> clientCertificates;
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public Optional<Contrast> contrast;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -693,10 +753,6 @@ public interface Browser extends AutoCloseable {
|
||||
public List<String> permissions;
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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;
|
||||
/**
|
||||
@@ -826,14 +882,42 @@ public interface Browser extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public NewPageOptions setClientCertificates(List<ClientCertificate> clientCertificates) {
|
||||
this.clientCertificates = clientCertificates;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public NewPageOptions setColorScheme(ColorScheme colorScheme) {
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public NewPageOptions setContrast(Contrast contrast) {
|
||||
this.contrast = Optional.ofNullable(contrast);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -941,20 +1025,12 @@ public interface Browser extends AutoCloseable {
|
||||
}
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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 NewPageOptions setProxy(String server) {
|
||||
return setProxy(new Proxy(server));
|
||||
}
|
||||
/**
|
||||
* Network proxy settings to use with this context. Defaults to none.
|
||||
*
|
||||
* <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 NewPageOptions setProxy(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
@@ -1179,10 +1255,10 @@ public interface Browser extends AutoCloseable {
|
||||
* <p> In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from the
|
||||
* browser server.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> This is similar to force quitting the browser. Therefore, you should call {@link
|
||||
* com.microsoft.playwright.BrowserContext#close BrowserContext.close()} on any {@code BrowserContext}'s you explicitly
|
||||
* created earlier with {@link com.microsoft.playwright.Browser#newContext Browser.newContext()} **before** calling {@link
|
||||
* com.microsoft.playwright.Browser#close Browser.close()}.
|
||||
* <p> <strong>NOTE:</strong> This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close events, call
|
||||
* {@link com.microsoft.playwright.BrowserContext#close BrowserContext.close()} on any {@code BrowserContext} instances you
|
||||
* explicitly created earlier using {@link com.microsoft.playwright.Browser#newContext Browser.newContext()} **before**
|
||||
* calling {@link com.microsoft.playwright.Browser#close Browser.close()}.
|
||||
*
|
||||
* <p> The {@code Browser} object itself is considered to be disposed and cannot be used anymore.
|
||||
*
|
||||
@@ -1198,10 +1274,10 @@ public interface Browser extends AutoCloseable {
|
||||
* <p> In case this browser is connected to, clears all created contexts belonging to this browser and disconnects from the
|
||||
* browser server.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> This is similar to force quitting the browser. Therefore, you should call {@link
|
||||
* com.microsoft.playwright.BrowserContext#close BrowserContext.close()} on any {@code BrowserContext}'s you explicitly
|
||||
* created earlier with {@link com.microsoft.playwright.Browser#newContext Browser.newContext()} **before** calling {@link
|
||||
* com.microsoft.playwright.Browser#close Browser.close()}.
|
||||
* <p> <strong>NOTE:</strong> This is similar to force-quitting the browser. To close pages gracefully and ensure you receive page close events, call
|
||||
* {@link com.microsoft.playwright.BrowserContext#close BrowserContext.close()} on any {@code BrowserContext} instances you
|
||||
* explicitly created earlier using {@link com.microsoft.playwright.Browser#newContext Browser.newContext()} **before**
|
||||
* calling {@link com.microsoft.playwright.Browser#close Browser.close()}.
|
||||
*
|
||||
* <p> The {@code Browser} object itself is considered to be disposed and cannot be used anymore.
|
||||
*
|
||||
@@ -1251,7 +1327,7 @@ public interface Browser extends AutoCloseable {
|
||||
* BrowserContext context = browser.newContext();
|
||||
* // Create a new page in a pristine context.
|
||||
* Page page = context.newPage();
|
||||
* page.navigate('https://example.com');
|
||||
* page.navigate("https://example.com");
|
||||
*
|
||||
* // Graceful close up everything
|
||||
* context.close();
|
||||
@@ -1278,7 +1354,7 @@ public interface Browser extends AutoCloseable {
|
||||
* BrowserContext context = browser.newContext();
|
||||
* // Create a new page in a pristine context.
|
||||
* Page page = context.newPage();
|
||||
* page.navigate('https://example.com');
|
||||
* page.navigate("https://example.com");
|
||||
*
|
||||
* // Graceful close up everything
|
||||
* context.close();
|
||||
@@ -1326,7 +1402,7 @@ public interface Browser extends AutoCloseable {
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* page.navigate("https://www.google.com");
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1350,7 +1426,7 @@ public interface Browser extends AutoCloseable {
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* page.navigate("https://www.google.com");
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1373,7 +1449,7 @@ public interface Browser extends AutoCloseable {
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* page.navigate("https://www.google.com");
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
@@ -30,8 +30,9 @@ import java.util.regex.Pattern;
|
||||
* <p> If a page opens another page, e.g. with a {@code window.open} call, the popup will belong to the parent page's browser
|
||||
* context.
|
||||
*
|
||||
* <p> Playwright allows creating "incognito" browser contexts with {@link com.microsoft.playwright.Browser#newContext
|
||||
* Browser.newContext()} method. "Incognito" browser contexts don't write any browsing data to disk.
|
||||
* <p> Playwright allows creating isolated non-persistent browser contexts with {@link
|
||||
* com.microsoft.playwright.Browser#newContext Browser.newContext()} method. Non-persistent browser contexts don't write
|
||||
* any browsing data to disk.
|
||||
* <pre>{@code
|
||||
* // Create a new incognito browser context
|
||||
* BrowserContext context = browser.newContext();
|
||||
@@ -406,12 +407,27 @@ public interface BrowserContext extends AutoCloseable {
|
||||
}
|
||||
}
|
||||
class StorageStateOptions {
|
||||
/**
|
||||
* Set to {@code true} to include <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> in
|
||||
* the storage state snapshot. If your application uses IndexedDB to store authentication tokens, like Firebase
|
||||
* Authentication, enable this.
|
||||
*/
|
||||
public Boolean indexedDB;
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
*/
|
||||
public Path path;
|
||||
|
||||
/**
|
||||
* Set to {@code true} to include <a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> in
|
||||
* the storage state snapshot. If your application uses IndexedDB to store authentication tokens, like Firebase
|
||||
* Authentication, enable this.
|
||||
*/
|
||||
public StorageStateOptions setIndexedDB(boolean indexedDB) {
|
||||
this.indexedDB = indexedDB;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
@@ -514,9 +530,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* browserContext.addCookies(Arrays.asList(cookieObject1, cookieObject2));
|
||||
* }</pre>
|
||||
*
|
||||
* @param cookies Adds cookies to the browser context.
|
||||
*
|
||||
* <p> For the cookie to apply to all subdomains as well, prefix domain with a dot, like this: ".example.com".
|
||||
* @since v1.8
|
||||
*/
|
||||
void addCookies(List<Cookie> cookies);
|
||||
@@ -703,7 +716,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType webkit = playwright.webkit()
|
||||
* BrowserType webkit = playwright.webkit();
|
||||
* Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.exposeBinding("pageURL", (source, args) -> source.page().url());
|
||||
@@ -750,7 +763,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType webkit = playwright.webkit()
|
||||
* BrowserType webkit = playwright.webkit();
|
||||
* Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.exposeBinding("pageURL", (source, args) -> source.page().url());
|
||||
@@ -799,8 +812,9 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType webkit = playwright.webkit()
|
||||
* BrowserType webkit = playwright.webkit();
|
||||
* Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false));
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.exposeFunction("sha256", args -> {
|
||||
* String text = (String) args[0];
|
||||
* MessageDigest crypto;
|
||||
@@ -835,10 +849,14 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if
|
||||
* specified.
|
||||
*
|
||||
* @param permissions A permission or an array of permissions to grant. Permissions can be one of the following values:
|
||||
* @param permissions A list of permissions to grant.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Supported permissions differ between browsers, and even between different versions of the same browser. Any permission
|
||||
* may stop working after an update.
|
||||
*
|
||||
* <p> Here are some permissions that may be supported by some browsers:
|
||||
* <ul>
|
||||
* <li> {@code "accelerometer"}</li>
|
||||
* <li> {@code "accessibility-events"}</li>
|
||||
* <li> {@code "ambient-light-sensor"}</li>
|
||||
* <li> {@code "background-sync"}</li>
|
||||
* <li> {@code "camera"}</li>
|
||||
@@ -863,10 +881,14 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if
|
||||
* specified.
|
||||
*
|
||||
* @param permissions A permission or an array of permissions to grant. Permissions can be one of the following values:
|
||||
* @param permissions A list of permissions to grant.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Supported permissions differ between browsers, and even between different versions of the same browser. Any permission
|
||||
* may stop working after an update.
|
||||
*
|
||||
* <p> Here are some permissions that may be supported by some browsers:
|
||||
* <ul>
|
||||
* <li> {@code "accelerometer"}</li>
|
||||
* <li> {@code "accessibility-events"}</li>
|
||||
* <li> {@code "ambient-light-sensor"}</li>
|
||||
* <li> {@code "background-sync"}</li>
|
||||
* <li> {@code "camera"}</li>
|
||||
@@ -929,7 +951,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -970,8 +992,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -985,7 +1007,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -1026,8 +1048,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1039,7 +1061,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -1080,8 +1102,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1095,7 +1117,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -1136,8 +1158,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1149,7 +1171,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -1190,8 +1212,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1205,7 +1227,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.BrowserContext#route BrowserContext.route()} will not intercept requests intercepted by
|
||||
* Service Worker. See <a href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling
|
||||
* Service Workers when using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* Service Workers when using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
@@ -1246,8 +1268,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* @param url A glob pattern, regex pattern, or predicate that receives a [URL] to match during routing. If {@code baseURL} is set in
|
||||
* the context options and the provided URL is a string that does not start with {@code *}, it is resolved using the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1259,7 +1281,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> Playwright will not serve requests intercepted by Service Worker from the HAR file. See <a
|
||||
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
|
||||
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code
|
||||
* path} is a relative path, then it is resolved relative to the current working directory.
|
||||
@@ -1274,13 +1296,94 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> Playwright will not serve requests intercepted by Service Worker from the HAR file. See <a
|
||||
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
|
||||
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
|
||||
* using request interception by setting {@code serviceWorkers} to {@code "block"}.
|
||||
*
|
||||
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code
|
||||
* path} is a relative path, then it is resolved relative to the current working directory.
|
||||
* @since v1.23
|
||||
*/
|
||||
void routeFromHAR(Path har, RouteFromHAROptions options);
|
||||
/**
|
||||
* This method allows to modify websocket connections that are made by any page in the browser context.
|
||||
*
|
||||
* <p> Note that only {@code WebSocket}s created after this method was called will be routed. It is recommended to call this
|
||||
* method before creating any pages.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Below is an example of a simple handler that blocks some websocket messages. See {@code WebSocketRoute} for more details
|
||||
* and examples.
|
||||
* <pre>{@code
|
||||
* context.routeWebSocket("/ws", ws -> {
|
||||
* ws.routeSend(message -> {
|
||||
* if ("to-be-blocked".equals(message))
|
||||
* return;
|
||||
* ws.send(message);
|
||||
* });
|
||||
* ws.connect();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Only WebSockets with the url matching this pattern will be routed. A string pattern can be relative to the {@code
|
||||
* baseURL} context option.
|
||||
* @param handler Handler function to route the WebSocket.
|
||||
* @since v1.48
|
||||
*/
|
||||
void routeWebSocket(String url, Consumer<WebSocketRoute> handler);
|
||||
/**
|
||||
* This method allows to modify websocket connections that are made by any page in the browser context.
|
||||
*
|
||||
* <p> Note that only {@code WebSocket}s created after this method was called will be routed. It is recommended to call this
|
||||
* method before creating any pages.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Below is an example of a simple handler that blocks some websocket messages. See {@code WebSocketRoute} for more details
|
||||
* and examples.
|
||||
* <pre>{@code
|
||||
* context.routeWebSocket("/ws", ws -> {
|
||||
* ws.routeSend(message -> {
|
||||
* if ("to-be-blocked".equals(message))
|
||||
* return;
|
||||
* ws.send(message);
|
||||
* });
|
||||
* ws.connect();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Only WebSockets with the url matching this pattern will be routed. A string pattern can be relative to the {@code
|
||||
* baseURL} context option.
|
||||
* @param handler Handler function to route the WebSocket.
|
||||
* @since v1.48
|
||||
*/
|
||||
void routeWebSocket(Pattern url, Consumer<WebSocketRoute> handler);
|
||||
/**
|
||||
* This method allows to modify websocket connections that are made by any page in the browser context.
|
||||
*
|
||||
* <p> Note that only {@code WebSocket}s created after this method was called will be routed. It is recommended to call this
|
||||
* method before creating any pages.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Below is an example of a simple handler that blocks some websocket messages. See {@code WebSocketRoute} for more details
|
||||
* and examples.
|
||||
* <pre>{@code
|
||||
* context.routeWebSocket("/ws", ws -> {
|
||||
* ws.routeSend(message -> {
|
||||
* if ("to-be-blocked".equals(message))
|
||||
* return;
|
||||
* ws.send(message);
|
||||
* });
|
||||
* ws.connect();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Only WebSockets with the url matching this pattern will be routed. A string pattern can be relative to the {@code
|
||||
* baseURL} context option.
|
||||
* @param handler Handler function to route the WebSocket.
|
||||
* @since v1.48
|
||||
*/
|
||||
void routeWebSocket(Predicate<String> url, Consumer<WebSocketRoute> handler);
|
||||
/**
|
||||
* This setting will change the default maximum navigation time for the following methods and related shortcuts:
|
||||
* <ul>
|
||||
@@ -1308,7 +1411,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* com.microsoft.playwright.BrowserContext#setDefaultNavigationTimeout BrowserContext.setDefaultNavigationTimeout()} take
|
||||
* priority over {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
|
||||
*
|
||||
* @param timeout Maximum time in milliseconds
|
||||
* @param timeout Maximum time in milliseconds. Pass {@code 0} to disable timeout.
|
||||
* @since v1.8
|
||||
*/
|
||||
void setDefaultTimeout(double timeout);
|
||||
@@ -1347,7 +1450,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
void setOffline(boolean offline);
|
||||
/**
|
||||
* Returns storage state for this browser context, contains current cookies and local storage snapshot.
|
||||
* Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB snapshot.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
@@ -1355,7 +1458,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
return storageState(null);
|
||||
}
|
||||
/**
|
||||
* Returns storage state for this browser context, contains current cookies and local storage snapshot.
|
||||
* Returns storage state for this browser context, contains current cookies, local storage snapshot and IndexedDB snapshot.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
|
||||
@@ -172,9 +172,14 @@ public interface BrowserType {
|
||||
*/
|
||||
public List<String> args;
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public Object channel;
|
||||
/**
|
||||
@@ -221,8 +226,8 @@ public interface BrowserType {
|
||||
/**
|
||||
* Whether to run browser in headless mode. More details for <a
|
||||
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
* href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public Boolean headless;
|
||||
/**
|
||||
@@ -265,18 +270,28 @@ public interface BrowserType {
|
||||
}
|
||||
@Deprecated
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public LaunchOptions setChannel(BrowserChannel channel) {
|
||||
this.channel = channel;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public LaunchOptions setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
@@ -353,8 +368,8 @@ public interface BrowserType {
|
||||
/**
|
||||
* Whether to run browser in headless mode. More details for <a
|
||||
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
* href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public LaunchOptions setHeadless(boolean headless) {
|
||||
this.headless = headless;
|
||||
@@ -446,9 +461,14 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean bypassCSP;
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public Object channel;
|
||||
/**
|
||||
@@ -456,11 +476,33 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean chromiumSandbox;
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public List<ClientCertificate> clientCertificates;
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public Optional<Contrast> contrast;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -522,8 +564,8 @@ public interface BrowserType {
|
||||
/**
|
||||
* Whether to run browser in headless mode. More details for <a
|
||||
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
* href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public Boolean headless;
|
||||
/**
|
||||
@@ -718,18 +760,28 @@ public interface BrowserType {
|
||||
}
|
||||
@Deprecated
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setChannel(BrowserChannel channel) {
|
||||
this.channel = channel;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge",
|
||||
* "msedge-beta", "msedge-dev", "msedge-canary". Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
* Browser distribution channel.
|
||||
*
|
||||
* <p> Use "chromium" to <a href="https://playwright.dev/java/docs/browsers#chromium-new-headless-mode">opt in to new headless
|
||||
* mode</a>.
|
||||
*
|
||||
* <p> Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", "msedge-dev", or "msedge-canary" to
|
||||
* use branded <a href="https://playwright.dev/java/docs/browsers#google-chrome--microsoft-edge">Google Chrome and
|
||||
* Microsoft Edge</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
@@ -743,14 +795,42 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing
|
||||
* {@code null} resets emulation to system defaults. Defaults to {@code "light"}.
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setClientCertificates(List<ClientCertificate> clientCertificates) {
|
||||
this.clientCertificates = clientCertificates;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-colors-scheme</a> media
|
||||
* feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code
|
||||
* "light"}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setColorScheme(ColorScheme colorScheme) {
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-contrast"} media feature, supported values are {@code "no-preference"}, {@code "more"}. See
|
||||
* {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setContrast(Contrast contrast) {
|
||||
this.contrast = Optional.ofNullable(contrast);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
@@ -854,8 +934,8 @@ public interface BrowserType {
|
||||
/**
|
||||
* Whether to run browser in headless mode. More details for <a
|
||||
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
* href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setHeadless(boolean headless) {
|
||||
this.headless = headless;
|
||||
@@ -1132,22 +1212,24 @@ public interface BrowserType {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via {@code
|
||||
* BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
|
||||
* compatible with 1.2.x).
|
||||
* This method attaches Playwright to an existing browser instance created via {@code BrowserType.launchServer} in Node.js.
|
||||
*
|
||||
* @param wsEndpoint A browser websocket endpoint to connect to.
|
||||
* <p> <strong>NOTE:</strong> The major and minor version of the Playwright instance that connects needs to match the version of Playwright that
|
||||
* launches the browser (1.2.3 → is compatible with 1.2.x).
|
||||
*
|
||||
* @param wsEndpoint A Playwright browser websocket endpoint to connect to. You obtain this endpoint via {@code BrowserServer.wsEndpoint}.
|
||||
* @since v1.8
|
||||
*/
|
||||
default Browser connect(String wsEndpoint) {
|
||||
return connect(wsEndpoint, null);
|
||||
}
|
||||
/**
|
||||
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via {@code
|
||||
* BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
|
||||
* compatible with 1.2.x).
|
||||
* This method attaches Playwright to an existing browser instance created via {@code BrowserType.launchServer} in Node.js.
|
||||
*
|
||||
* @param wsEndpoint A browser websocket endpoint to connect to.
|
||||
* <p> <strong>NOTE:</strong> The major and minor version of the Playwright instance that connects needs to match the version of Playwright that
|
||||
* launches the browser (1.2.3 → is compatible with 1.2.x).
|
||||
*
|
||||
* @param wsEndpoint A Playwright browser websocket endpoint to connect to. You obtain this endpoint via {@code BrowserServer.wsEndpoint}.
|
||||
* @since v1.8
|
||||
*/
|
||||
Browser connect(String wsEndpoint, ConnectOptions options);
|
||||
@@ -1158,6 +1240,11 @@ public interface BrowserType {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> This connection is significantly lower fidelity than the Playwright protocol connection via {@link
|
||||
* com.microsoft.playwright.BrowserType#connect BrowserType.connect()}. If you are experiencing issues or attempting to use
|
||||
* advanced functionality, you probably want to use {@link com.microsoft.playwright.BrowserType#connect
|
||||
* BrowserType.connect()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
|
||||
@@ -1179,6 +1266,11 @@ public interface BrowserType {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> This connection is significantly lower fidelity than the Playwright protocol connection via {@link
|
||||
* com.microsoft.playwright.BrowserType#connect BrowserType.connect()}. If you are experiencing issues or attempting to use
|
||||
* advanced functionality, you probably want to use {@link com.microsoft.playwright.BrowserType#connect
|
||||
* BrowserType.connect()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
|
||||
@@ -1273,11 +1365,15 @@ public interface BrowserType {
|
||||
* <p> Launches browser that uses persistent storage located at {@code userDataDir} and returns the only context. Closing this
|
||||
* context will automatically close the browser.
|
||||
*
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. Pass an empty string to
|
||||
* create a temporary directory.
|
||||
*
|
||||
* <p> More details for <a
|
||||
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
|
||||
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
|
||||
* an empty string to use a temporary directory instead.
|
||||
* href="https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile">Firefox</a>. Chromium's user data directory is
|
||||
* the **parent** directory of the "Profile Path" seen at {@code chrome://version}.
|
||||
*
|
||||
* <p> Note that browsers do not allow launching multiple instances with the same User Data Directory.
|
||||
* @since v1.8
|
||||
*/
|
||||
default BrowserContext launchPersistentContext(Path userDataDir) {
|
||||
@@ -1289,11 +1385,15 @@ public interface BrowserType {
|
||||
* <p> Launches browser that uses persistent storage located at {@code userDataDir} and returns the only context. Closing this
|
||||
* context will automatically close the browser.
|
||||
*
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. Pass an empty string to
|
||||
* create a temporary directory.
|
||||
*
|
||||
* <p> More details for <a
|
||||
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
|
||||
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
|
||||
* an empty string to use a temporary directory instead.
|
||||
* href="https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile">Firefox</a>. Chromium's user data directory is
|
||||
* the **parent** directory of the "Profile Path" seen at {@code chrome://version}.
|
||||
*
|
||||
* <p> Note that browsers do not allow launching multiple instances with the same User Data Directory.
|
||||
* @since v1.8
|
||||
*/
|
||||
BrowserContext launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options);
|
||||
|
||||
@@ -174,6 +174,19 @@ public interface Clock {
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
@@ -194,6 +207,19 @@ public interface Clock {
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
@@ -214,6 +240,19 @@ public interface Clock {
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
@@ -227,6 +266,10 @@ public interface Clock {
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
@@ -241,6 +284,10 @@ public interface Clock {
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
@@ -255,6 +302,10 @@ public interface Clock {
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
@@ -267,7 +318,8 @@ public interface Clock {
|
||||
*/
|
||||
void setFixedTime(Date time);
|
||||
/**
|
||||
* Sets current system time but does not trigger any timers.
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
@@ -281,7 +333,8 @@ public interface Clock {
|
||||
*/
|
||||
void setSystemTime(long time);
|
||||
/**
|
||||
* Sets current system time but does not trigger any timers.
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
@@ -295,7 +348,8 @@ public interface Clock {
|
||||
*/
|
||||
void setSystemTime(String time);
|
||||
/**
|
||||
* Sets current system time but does not trigger any timers.
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
|
||||
@@ -39,8 +39,8 @@ import java.util.*;
|
||||
* });
|
||||
*
|
||||
* // Deconstruct console.log arguments
|
||||
* msg.args().get(0).jsonValue() // hello
|
||||
* msg.args().get(1).jsonValue() // 42
|
||||
* msg.args().get(0).jsonValue(); // hello
|
||||
* msg.args().get(1).jsonValue(); // 42
|
||||
* }</pre>
|
||||
*/
|
||||
public interface ConsoleMessage {
|
||||
|
||||
@@ -65,9 +65,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -98,9 +96,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public CheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -166,9 +162,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -229,9 +223,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public ClickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -293,9 +285,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -349,9 +339,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public DblclickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -399,9 +387,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -421,9 +407,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public FillOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -453,9 +437,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -495,9 +477,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public HoverOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -564,9 +544,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -585,9 +563,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public PressOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -623,7 +599,9 @@ public interface ElementHandle extends JSHandle {
|
||||
public ScreenshotCaret caret;
|
||||
/**
|
||||
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box.
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box. The mask is also applied to
|
||||
* invisible elements, see <a href="https://playwright.dev/java/docs/locators#matching-only-visible-elements">Matching only
|
||||
* visible elements</a> to disable that.
|
||||
*/
|
||||
public List<Locator> mask;
|
||||
/**
|
||||
@@ -697,7 +675,9 @@ public interface ElementHandle extends JSHandle {
|
||||
}
|
||||
/**
|
||||
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box.
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box. The mask is also applied to
|
||||
* invisible elements, see <a href="https://playwright.dev/java/docs/locators#matching-only-visible-elements">Matching only
|
||||
* visible elements</a> to disable that.
|
||||
*/
|
||||
public ScreenshotOptions setMask(List<Locator> mask) {
|
||||
this.mask = mask;
|
||||
@@ -801,9 +781,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -823,9 +801,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SelectOptionOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -882,9 +858,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -915,9 +889,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetCheckedOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -960,9 +932,7 @@ public interface ElementHandle extends JSHandle {
|
||||
}
|
||||
class SetInputFilesOptions {
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -974,9 +944,7 @@ public interface ElementHandle extends JSHandle {
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetInputFilesOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1006,9 +974,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1048,9 +1014,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TapOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1097,9 +1061,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1118,9 +1080,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TypeOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1144,9 +1104,7 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1177,9 +1135,7 @@ public interface ElementHandle extends JSHandle {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public UncheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1332,7 +1288,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -1355,7 +1310,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -1421,8 +1375,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -1445,8 +1397,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -1703,7 +1653,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -1724,7 +1673,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -2340,7 +2288,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2362,7 +2309,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2501,7 +2447,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -2524,7 +2469,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -2572,7 +2516,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2595,7 +2538,6 @@ public interface ElementHandle extends JSHandle {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
|
||||
@@ -30,9 +30,7 @@ import java.nio.file.Path;
|
||||
public interface FileChooser {
|
||||
class SetFilesOptions {
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -44,9 +42,7 @@ public interface FileChooser {
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetFilesOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
|
||||
@@ -72,7 +72,7 @@ public interface Frame {
|
||||
*/
|
||||
public Path path;
|
||||
/**
|
||||
* Script type. Use 'module' in order to load a Javascript ES6 module. See <a
|
||||
* Script type. Use 'module' in order to load a JavaScript ES6 module. See <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script">script</a> for more details.
|
||||
*/
|
||||
public String type;
|
||||
@@ -97,7 +97,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Script type. Use 'module' in order to load a Javascript ES6 module. See <a
|
||||
* Script type. Use 'module' in order to load a JavaScript ES6 module. See <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script">script</a> for more details.
|
||||
*/
|
||||
public AddScriptTagOptions setType(String type) {
|
||||
@@ -157,9 +157,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -195,9 +193,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public CheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -271,9 +267,7 @@ public interface Frame {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -296,7 +290,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -339,9 +334,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public ClickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -383,7 +376,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public ClickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -411,9 +405,7 @@ public interface Frame {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -436,7 +428,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -472,9 +465,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public DblclickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -516,7 +507,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public DblclickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -563,9 +555,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -606,9 +596,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public DragAndDropOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -695,9 +683,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -722,9 +708,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public FillOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1124,9 +1108,7 @@ public interface Frame {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1149,7 +1131,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -1171,9 +1154,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public HoverOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1215,7 +1196,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public HoverOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -1613,9 +1595,7 @@ public interface Frame {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1639,9 +1619,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public PressOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1689,9 +1667,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1716,9 +1692,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SelectOptionOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1750,9 +1724,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1788,9 +1760,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetCheckedOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1890,9 +1860,7 @@ public interface Frame {
|
||||
}
|
||||
class SetInputFilesOptions {
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1909,9 +1877,7 @@ public interface Frame {
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetInputFilesOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1949,9 +1915,7 @@ public interface Frame {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1974,7 +1938,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -1996,9 +1961,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TapOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -2040,7 +2003,8 @@ public interface Frame {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public TapOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -2086,9 +2050,7 @@ public interface Frame {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -2112,9 +2074,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TypeOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -2146,9 +2106,7 @@ public interface Frame {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -2184,9 +2142,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public UncheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -2531,7 +2487,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2554,7 +2509,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2625,9 +2579,8 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throw.</li>
|
||||
* specified {@code position}. if the first 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 throws a {@code
|
||||
@@ -2649,9 +2602,8 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throw.</li>
|
||||
* specified {@code position}. if the first 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 throws a {@code
|
||||
@@ -3547,19 +3499,19 @@ public interface Frame {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3589,19 +3541,19 @@ public interface Frame {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3629,19 +3581,19 @@ public interface Frame {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3671,19 +3623,19 @@ public interface Frame {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3831,7 +3783,6 @@ public interface Frame {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
|
||||
@@ -3852,7 +3803,6 @@ public interface Frame {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
|
||||
@@ -4568,7 +4518,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -4592,7 +4541,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -4753,7 +4701,6 @@ public interface Frame {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
|
||||
@@ -4776,7 +4723,6 @@ public interface Frame {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
|
||||
@@ -4842,7 +4788,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -4865,7 +4810,6 @@ public interface Frame {
|
||||
* 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 com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
|
||||
@@ -22,10 +22,10 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* FrameLocator represents a view to the {@code iframe} on the page. It captures the logic sufficient to retrieve the
|
||||
* {@code iframe} and locate elements in that iframe. FrameLocator can be created with either {@link
|
||||
* com.microsoft.playwright.Page#frameLocator Page.frameLocator()} or {@link com.microsoft.playwright.Locator#frameLocator
|
||||
* Locator.frameLocator()} method.
|
||||
* com.microsoft.playwright.Locator#contentFrame Locator.contentFrame()}, {@link com.microsoft.playwright.Page#frameLocator
|
||||
* Page.frameLocator()} or {@link com.microsoft.playwright.Locator#frameLocator Locator.frameLocator()} method.
|
||||
* <pre>{@code
|
||||
* Locator locator = page.frameLocator("#my-frame").getByText("Submit");
|
||||
* Locator locator = page.locator("#my-frame").contentFrame().getByText("Submit");
|
||||
* locator.click();
|
||||
* }</pre>
|
||||
*
|
||||
@@ -35,10 +35,10 @@ import java.util.regex.Pattern;
|
||||
* a given selector.
|
||||
* <pre>{@code
|
||||
* // Throws if there are several frames in DOM:
|
||||
* page.frame_locator(".result-frame").getByRole(AriaRole.BUTTON).click();
|
||||
* page.locator(".result-frame").contentFrame().getByRole(AriaRole.BUTTON).click();
|
||||
*
|
||||
* // Works because we explicitly tell locator to pick the first frame:
|
||||
* page.frame_locator(".result-frame").first().getByRole(AriaRole.BUTTON).click();
|
||||
* page.locator(".result-frame").first().contentFrame().getByRole(AriaRole.BUTTON).click();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Converting Locator to FrameLocator</strong>
|
||||
@@ -383,7 +383,8 @@ public interface FrameLocator {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns locator to the first matching frame.
|
||||
* @deprecated Use {@link com.microsoft.playwright.Locator#first Locator.first()} followed by {@link
|
||||
* com.microsoft.playwright.Locator#contentFrame Locator.contentFrame()} instead.
|
||||
*
|
||||
* @since v1.17
|
||||
*/
|
||||
@@ -733,19 +734,19 @@ public interface FrameLocator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -775,19 +776,19 @@ public interface FrameLocator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -815,19 +816,19 @@ public interface FrameLocator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -857,19 +858,19 @@ public interface FrameLocator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -953,7 +954,8 @@ public interface FrameLocator {
|
||||
*/
|
||||
Locator getByTitle(Pattern text, GetByTitleOptions options);
|
||||
/**
|
||||
* Returns locator to the last matching frame.
|
||||
* @deprecated Use {@link com.microsoft.playwright.Locator#last Locator.last()} followed by {@link
|
||||
* com.microsoft.playwright.Locator#contentFrame Locator.contentFrame()} instead.
|
||||
*
|
||||
* @since v1.17
|
||||
*/
|
||||
@@ -1003,7 +1005,8 @@ public interface FrameLocator {
|
||||
*/
|
||||
Locator locator(Locator selectorOrLocator, LocatorOptions options);
|
||||
/**
|
||||
* Returns locator to the n-th matching frame. It's zero based, {@code nth(0)} selects the first frame.
|
||||
* @deprecated Use {@link com.microsoft.playwright.Locator#nth Locator.nth()} followed by {@link
|
||||
* com.microsoft.playwright.Locator#contentFrame Locator.contentFrame()} instead.
|
||||
*
|
||||
* @since v1.17
|
||||
*/
|
||||
@@ -1018,7 +1021,7 @@ public interface FrameLocator {
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* FrameLocator frameLocator = page.frameLocator("iframe[name=\"embedded\"]");
|
||||
* FrameLocator frameLocator = page.locator("iframe[name=\"embedded\"]").contentFrame();
|
||||
* // ...
|
||||
* Locator locator = frameLocator.owner();
|
||||
* assertThat(locator).isVisible();
|
||||
|
||||
@@ -48,10 +48,7 @@ import com.microsoft.playwright.options.*;
|
||||
*
|
||||
* <p> An example to trigger select-all with the keyboard
|
||||
* <pre>{@code
|
||||
* // on Windows and Linux
|
||||
* page.keyboard().press("Control+A");
|
||||
* // on macOS
|
||||
* page.keyboard().press("Meta+A");
|
||||
* page.keyboard().press("ControlOrMeta+A");
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Keyboard {
|
||||
@@ -164,7 +161,7 @@ public interface Keyboard {
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
* page.keyboard().press("A");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"));
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")));
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png")));
|
||||
* page.keyboard().press("Shift+O");
|
||||
@@ -211,7 +208,7 @@ public interface Keyboard {
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
* page.keyboard().press("A");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"));
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")));
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png")));
|
||||
* page.keyboard().press("Shift+O");
|
||||
|
||||
@@ -29,6 +29,39 @@ import java.util.regex.Pattern;
|
||||
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
|
||||
*/
|
||||
public interface Locator {
|
||||
class AriaSnapshotOptions {
|
||||
/**
|
||||
* Generate symbolic reference for each element. One can use {@code aria-ref=<ref>} locator immediately after capturing the
|
||||
* snapshot to perform actions on the element.
|
||||
*/
|
||||
public Boolean ref;
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Generate symbolic reference for each element. One can use {@code aria-ref=<ref>} locator immediately after capturing the
|
||||
* snapshot to perform actions on the element.
|
||||
*/
|
||||
public AriaSnapshotOptions setRef(boolean ref) {
|
||||
this.ref = ref;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
*/
|
||||
public AriaSnapshotOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class BlurOptions {
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
@@ -76,9 +109,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -109,9 +140,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public CheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -159,9 +188,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -181,9 +208,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public ClearOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -225,9 +250,7 @@ public interface Locator {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -245,7 +268,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -288,9 +312,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public ClickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -324,7 +346,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public ClickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -352,9 +375,7 @@ public interface Locator {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -372,7 +393,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -408,9 +430,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public DblclickOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -444,7 +464,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public DblclickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -478,9 +499,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -516,9 +535,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public DragToOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -596,18 +613,14 @@ public interface Locator {
|
||||
}
|
||||
class EvaluateOptions {
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
* Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
|
||||
* itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
* Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
|
||||
* itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public EvaluateOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -616,18 +629,14 @@ public interface Locator {
|
||||
}
|
||||
class EvaluateHandleOptions {
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
* Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
|
||||
* itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
* Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
|
||||
* itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public EvaluateHandleOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -641,9 +650,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -663,9 +670,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public FillOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -715,6 +720,10 @@ public interface Locator {
|
||||
* <article><div>Playwright</div></article>}.
|
||||
*/
|
||||
public Object hasText;
|
||||
/**
|
||||
* Only matches visible or invisible elements.
|
||||
*/
|
||||
public Boolean visible;
|
||||
|
||||
/**
|
||||
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||
@@ -777,6 +786,13 @@ public interface Locator {
|
||||
this.hasText = hasText;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Only matches visible or invisible elements.
|
||||
*/
|
||||
public FilterOptions setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FocusOptions {
|
||||
/**
|
||||
@@ -1065,9 +1081,7 @@ public interface Locator {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1085,7 +1099,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -1107,9 +1122,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public HoverOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1143,7 +1156,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public HoverOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -1424,9 +1438,7 @@ public interface Locator {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1445,9 +1457,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option will default to {@code true} in the future.
|
||||
*/
|
||||
public PressOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1470,9 +1480,7 @@ public interface Locator {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1491,9 +1499,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public PressSequentiallyOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1529,7 +1535,9 @@ public interface Locator {
|
||||
public ScreenshotCaret caret;
|
||||
/**
|
||||
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box.
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box. The mask is also applied to
|
||||
* invisible elements, see <a href="https://playwright.dev/java/docs/locators#matching-only-visible-elements">Matching only
|
||||
* visible elements</a> to disable that.
|
||||
*/
|
||||
public List<Locator> mask;
|
||||
/**
|
||||
@@ -1603,7 +1611,9 @@ public interface Locator {
|
||||
}
|
||||
/**
|
||||
* Specify locators that should be masked when the screenshot is taken. Masked elements will be overlaid with a pink box
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box.
|
||||
* {@code #FF00FF} (customized by {@code maskColor}) that completely covers its bounding box. The mask is also applied to
|
||||
* invisible elements, see <a href="https://playwright.dev/java/docs/locators#matching-only-visible-elements">Matching only
|
||||
* visible elements</a> to disable that.
|
||||
*/
|
||||
public ScreenshotOptions setMask(List<Locator> mask) {
|
||||
this.mask = mask;
|
||||
@@ -1707,9 +1717,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1729,9 +1737,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SelectOptionOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1788,9 +1794,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1821,9 +1825,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetCheckedOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1866,9 +1868,7 @@ public interface Locator {
|
||||
}
|
||||
class SetInputFilesOptions {
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1880,9 +1880,7 @@ public interface Locator {
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetInputFilesOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1912,9 +1910,7 @@ public interface Locator {
|
||||
*/
|
||||
public List<KeyboardModifier> modifiers;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -1932,7 +1928,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
@@ -1954,9 +1951,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TapOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -1990,7 +1985,8 @@ public interface Locator {
|
||||
/**
|
||||
* 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.
|
||||
* performing it. Note that keyboard {@code modifiers} will be pressed regardless of {@code trial} to allow testing
|
||||
* elements which are only visible when those keys are pressed.
|
||||
*/
|
||||
public TapOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
@@ -2023,9 +2019,7 @@ public interface Locator {
|
||||
*/
|
||||
public Double delay;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -2044,9 +2038,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public TypeOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -2070,9 +2062,7 @@ public interface Locator {
|
||||
*/
|
||||
public Boolean force;
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
@@ -2103,9 +2093,7 @@ public interface Locator {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public UncheckOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
@@ -2197,14 +2185,13 @@ public interface Locator {
|
||||
* When the locator points to a list of elements, this returns an array of locators, pointing to their respective elements.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.Locator#all Locator.all()} does not wait for elements to match the locator, and instead
|
||||
* immediately returns whatever is present in the page. When the list of elements changes dynamically, {@link
|
||||
* com.microsoft.playwright.Locator#all Locator.all()} will produce unpredictable and flaky results. When the list of
|
||||
* elements is stable, but loaded dynamically, wait for the full list to finish loading before calling {@link
|
||||
* com.microsoft.playwright.Locator#all Locator.all()}.
|
||||
* immediately returns whatever is present in the page.When the list of elements changes dynamically, {@link com.microsoft.playwright.Locator#all Locator.all()} will produce
|
||||
* unpredictable and flaky results.When the list of elements is stable, but loaded dynamically, wait for the full list to finish loading before calling
|
||||
* {@link com.microsoft.playwright.Locator#all Locator.all()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* for (Locator li : page.getByRole('listitem').all())
|
||||
* for (Locator li : page.getByRole("listitem").all())
|
||||
* li.click();
|
||||
* }</pre>
|
||||
*
|
||||
@@ -2255,6 +2242,66 @@ public interface Locator {
|
||||
* @since v1.34
|
||||
*/
|
||||
Locator and(Locator locator);
|
||||
/**
|
||||
* Captures the aria snapshot of the given element. Read more about <a
|
||||
* href="https://playwright.dev/java/docs/aria-snapshots">aria snapshots</a> and {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#matchesAriaSnapshot LocatorAssertions.matchesAriaSnapshot()} for
|
||||
* the corresponding assertion.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.getByRole(AriaRole.LINK).ariaSnapshot();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> This method captures the aria snapshot of the given element. The snapshot is a string that represents the state of the
|
||||
* element and its children. The snapshot can be used to assert the state of the element in the test, or to compare it to
|
||||
* state in the future.
|
||||
*
|
||||
* <p> The ARIA snapshot is represented using <a href="https://yaml.org/spec/1.2.2/">YAML</a> markup language:
|
||||
* <ul>
|
||||
* <li> The keys of the objects are the roles and optional accessible names of the elements.</li>
|
||||
* <li> The values are either text content or an array of child elements.</li>
|
||||
* <li> Generic static text can be represented with the {@code text} key.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Below is the HTML markup and the respective ARIA snapshot:
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
default String ariaSnapshot() {
|
||||
return ariaSnapshot(null);
|
||||
}
|
||||
/**
|
||||
* Captures the aria snapshot of the given element. Read more about <a
|
||||
* href="https://playwright.dev/java/docs/aria-snapshots">aria snapshots</a> and {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#matchesAriaSnapshot LocatorAssertions.matchesAriaSnapshot()} for
|
||||
* the corresponding assertion.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.getByRole(AriaRole.LINK).ariaSnapshot();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> This method captures the aria snapshot of the given element. The snapshot is a string that represents the state of the
|
||||
* element and its children. The snapshot can be used to assert the state of the element in the test, or to compare it to
|
||||
* state in the future.
|
||||
*
|
||||
* <p> The ARIA snapshot is represented using <a href="https://yaml.org/spec/1.2.2/">YAML</a> markup language:
|
||||
* <ul>
|
||||
* <li> The keys of the objects are the roles and optional accessible names of the elements.</li>
|
||||
* <li> The values are either text content or an array of child elements.</li>
|
||||
* <li> Generic static text can be represented with the {@code text} key.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Below is the HTML markup and the respective ARIA snapshot:
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
String ariaSnapshot(AriaSnapshotOptions options);
|
||||
/**
|
||||
* Calls <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur">blur</a> on the element.
|
||||
*
|
||||
@@ -2334,7 +2381,6 @@ public interface Locator {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2366,7 +2412,6 @@ public interface Locator {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -2532,8 +2577,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -2560,8 +2603,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -2609,7 +2650,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> You can also specify {@code JSHandle} as the property value if you want live objects to be passed into the event:
|
||||
* <pre>{@code
|
||||
* // Note you can only create DataTransfer in Chromium and Firefox
|
||||
* JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
|
||||
* Map<String, Object> arg = new HashMap<>();
|
||||
* arg.put("dataTransfer", dataTransfer);
|
||||
@@ -2658,7 +2698,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> You can also specify {@code JSHandle} as the property value if you want live objects to be passed into the event:
|
||||
* <pre>{@code
|
||||
* // Note you can only create DataTransfer in Chromium and Firefox
|
||||
* JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
|
||||
* Map<String, Object> arg = new HashMap<>();
|
||||
* arg.put("dataTransfer", dataTransfer);
|
||||
@@ -2706,7 +2745,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> You can also specify {@code JSHandle} as the property value if you want live objects to be passed into the event:
|
||||
* <pre>{@code
|
||||
* // Note you can only create DataTransfer in Chromium and Firefox
|
||||
* JSHandle dataTransfer = page.evaluateHandle("() => new DataTransfer()");
|
||||
* Map<String, Object> arg = new HashMap<>();
|
||||
* arg.put("dataTransfer", dataTransfer);
|
||||
@@ -2822,10 +2860,6 @@ public interface Locator {
|
||||
* <p> If {@code expression} throws or rejects, this method throws.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator tweets = page.locator(".tweet .retweets");
|
||||
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
@@ -2850,10 +2884,6 @@ public interface Locator {
|
||||
* <p> If {@code expression} throws or rejects, this method throws.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator tweets = page.locator(".tweet .retweets");
|
||||
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
@@ -2877,10 +2907,6 @@ public interface Locator {
|
||||
* <p> If {@code expression} throws or rejects, this method throws.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator tweets = page.locator(".tweet .retweets");
|
||||
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
@@ -3514,19 +3540,19 @@ public interface Locator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3556,19 +3582,19 @@ public interface Locator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3596,19 +3622,19 @@ public interface Locator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3638,19 +3664,19 @@ public interface Locator {
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
* page.getByText("world");
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
* page.getByText("Hello world");
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true));
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
* page.getByText(Pattern.compile("Hello"));
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
|
||||
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
@@ -3757,7 +3783,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -3787,7 +3812,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#mouse Page.mouse()} to hover over 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -3949,7 +3973,9 @@ public interface Locator {
|
||||
*/
|
||||
boolean isDisabled(IsDisabledOptions options);
|
||||
/**
|
||||
* Returns whether the element is <a href="https://playwright.dev/java/docs/actionability#editable">editable</a>.
|
||||
* Returns whether the element is <a href="https://playwright.dev/java/docs/actionability#editable">editable</a>. If the
|
||||
* target element is not an {@code <input>}, {@code <textarea>}, {@code <select>}, {@code [contenteditable]} and does not
|
||||
* have a role allowing {@code [aria-readonly]}, this method throws an error.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If you need to assert that an element is editable, prefer {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#isEditable LocatorAssertions.isEditable()} to avoid flakiness. See
|
||||
@@ -3966,7 +3992,9 @@ public interface Locator {
|
||||
return isEditable(null);
|
||||
}
|
||||
/**
|
||||
* Returns whether the element is <a href="https://playwright.dev/java/docs/actionability#editable">editable</a>.
|
||||
* Returns whether the element is <a href="https://playwright.dev/java/docs/actionability#editable">editable</a>. If the
|
||||
* target element is not an {@code <input>}, {@code <textarea>}, {@code <select>}, {@code [contenteditable]} and does not
|
||||
* have a role allowing {@code [aria-readonly]}, this method throws an error.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If you need to assert that an element is editable, prefer {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#isEditable LocatorAssertions.isEditable()} to avoid flakiness. See
|
||||
@@ -4145,16 +4173,23 @@ public interface Locator {
|
||||
*/
|
||||
Locator nth(int index);
|
||||
/**
|
||||
* Creates a locator that matches either of the two locators.
|
||||
* Creates a locator matching all elements that match one or both of the two locators.
|
||||
*
|
||||
* <p> Note that when both locators match something, the resulting locator will have multiple matches, potentially causing a <a
|
||||
* href="https://playwright.dev/java/docs/locators#strictness">locator strictness</a> violation.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Consider a scenario where you'd like to click on a "New email" button, but sometimes a security settings dialog shows up
|
||||
* instead. In this case, you can wait for either a "New email" button, or a dialog and act accordingly.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If both "New email" button and security dialog appear on screen, the "or" locator will match both of them, possibly
|
||||
* throwing the <a href="https://playwright.dev/java/docs/locators#strictness">"strict mode violation" error</a>. In this
|
||||
* case, you can use {@link com.microsoft.playwright.Locator#first Locator.first()} to only match one of them.
|
||||
* <pre>{@code
|
||||
* Locator newEmail = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("New"));
|
||||
* Locator dialog = page.getByText("Confirm security settings");
|
||||
* assertThat(newEmail.or(dialog)).isVisible();
|
||||
* assertThat(newEmail.or(dialog).first()).isVisible();
|
||||
* if (dialog.isVisible())
|
||||
* page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Dismiss")).click();
|
||||
* newEmail.click();
|
||||
@@ -4840,7 +4875,6 @@ public interface Locator {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -4871,7 +4905,6 @@ public interface Locator {
|
||||
* 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 com.microsoft.playwright.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 or unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -5187,7 +5220,9 @@ public interface Locator {
|
||||
*/
|
||||
void setInputFiles(FilePayload[] files, SetInputFilesOptions options);
|
||||
/**
|
||||
* Perform a tap gesture on the element matching the locator.
|
||||
* Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually
|
||||
* dispatching touch events, see the <a href="https://playwright.dev/java/docs/touch-events">emulating legacy touch
|
||||
* events</a> page.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
@@ -5198,7 +5233,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -5214,7 +5248,9 @@ public interface Locator {
|
||||
tap(null);
|
||||
}
|
||||
/**
|
||||
* Perform a tap gesture on the element matching the locator.
|
||||
* Perform a tap gesture on the element matching the locator. For examples of emulating other gestures by manually
|
||||
* dispatching touch events, see the <a href="https://playwright.dev/java/docs/touch-events">emulating legacy touch
|
||||
* events</a> page.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
@@ -5225,7 +5261,6 @@ public interface Locator {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.Page#touchscreen Page.touchscreen()} to tap 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.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
@@ -5298,7 +5333,6 @@ public interface Locator {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
@@ -5330,7 +5364,6 @@ public interface Locator {
|
||||
* force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link com.microsoft.playwright.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 throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
|
||||
@@ -163,6 +163,8 @@ public interface Mouse {
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void click(double x, double y) {
|
||||
@@ -172,6 +174,8 @@ public interface Mouse {
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void click(double x, double y, ClickOptions options);
|
||||
@@ -180,6 +184,8 @@ public interface Mouse {
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()} and {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void dblclick(double x, double y) {
|
||||
@@ -190,6 +196,8 @@ public interface Mouse {
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()} and {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void dblclick(double x, double y, DblclickOptions options);
|
||||
@@ -210,6 +218,8 @@ public interface Mouse {
|
||||
/**
|
||||
* Dispatches a {@code mousemove} event.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void move(double x, double y) {
|
||||
@@ -218,6 +228,8 @@ public interface Mouse {
|
||||
/**
|
||||
* Dispatches a {@code mousemove} event.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void move(double x, double y, MoveOptions options);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -99,7 +99,7 @@ public interface Request {
|
||||
*/
|
||||
List<HttpHeader> headersArray();
|
||||
/**
|
||||
* Returns the value of the header matching the name. The name is case insensitive.
|
||||
* Returns the value of the header matching the name. The name is case-insensitive.
|
||||
*
|
||||
* @param name Name of the header.
|
||||
* @since v1.15
|
||||
|
||||
@@ -71,7 +71,7 @@ public interface Response {
|
||||
*/
|
||||
List<HttpHeader> headersArray();
|
||||
/**
|
||||
* Returns the value of the header matching the name. The name is case insensitive. If multiple headers have the same name
|
||||
* Returns the value of the header matching the name. The name is case-insensitive. If multiple headers have the same name
|
||||
* (except {@code set-cookie}), they are returned as a list separated by {@code , }. For {@code set-cookie}, the {@code \n}
|
||||
* separator is used. If no headers are found, {@code null} is returned.
|
||||
*
|
||||
@@ -80,7 +80,7 @@ public interface Response {
|
||||
*/
|
||||
String headerValue(String name);
|
||||
/**
|
||||
* Returns all values of the headers matching the name, for example {@code set-cookie}. The name is case insensitive.
|
||||
* Returns all values of the headers matching the name, for example {@code set-cookie}. The name is case-insensitive.
|
||||
*
|
||||
* @param name Name of the header.
|
||||
* @since v1.15
|
||||
|
||||
@@ -147,6 +147,12 @@ public interface Route {
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
|
||||
*/
|
||||
public Integer maxRedirects;
|
||||
/**
|
||||
* Maximum number of times network errors should be retried. Currently only {@code ECONNRESET} error is retried. Does not
|
||||
* retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to {@code 0} - no
|
||||
* retries.
|
||||
*/
|
||||
public Integer maxRetries;
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
@@ -179,6 +185,15 @@ public interface Route {
|
||||
this.maxRedirects = maxRedirects;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum number of times network errors should be retried. Currently only {@code ECONNRESET} error is retried. Does not
|
||||
* retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to {@code 0} - no
|
||||
* retries.
|
||||
*/
|
||||
public FetchOptions setMaxRetries(int maxRetries) {
|
||||
this.maxRetries = maxRetries;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
@@ -333,7 +348,7 @@ public interface Route {
|
||||
*/
|
||||
void abort(String errorCode);
|
||||
/**
|
||||
* Continues route's request with optional overrides.
|
||||
* Sends route's request to the network with optional overrides.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
@@ -348,10 +363,16 @@ public interface Route {
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
|
||||
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
|
||||
* through redirects, use the combination of {@link com.microsoft.playwright.Route#fetch Route.fetch()} and {@link
|
||||
* com.microsoft.playwright.Route#fulfill Route.fulfill()} instead.
|
||||
* <p> The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url},
|
||||
* {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests.
|
||||
*
|
||||
* <p> {@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other
|
||||
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
|
||||
* next matching handler in the chain to be invoked.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The {@code Cookie} header cannot be overridden using this method. If a value is provided, it will be ignored, and the
|
||||
* cookie will be loaded from the browser's cookie store. To set custom cookies, use {@link
|
||||
* com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
@@ -359,7 +380,7 @@ public interface Route {
|
||||
resume(null);
|
||||
}
|
||||
/**
|
||||
* Continues route's request with optional overrides.
|
||||
* Sends route's request to the network with optional overrides.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
@@ -374,21 +395,30 @@ public interface Route {
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
|
||||
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
|
||||
* through redirects, use the combination of {@link com.microsoft.playwright.Route#fetch Route.fetch()} and {@link
|
||||
* com.microsoft.playwright.Route#fulfill Route.fulfill()} instead.
|
||||
* <p> The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url},
|
||||
* {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests.
|
||||
*
|
||||
* <p> {@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other
|
||||
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
|
||||
* next matching handler in the chain to be invoked.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The {@code Cookie} header cannot be overridden using this method. If a value is provided, it will be ignored, and the
|
||||
* cookie will be loaded from the browser's cookie store. To set custom cookies, use {@link
|
||||
* com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void resume(ResumeOptions options);
|
||||
/**
|
||||
* When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* Continues route's request with optional overrides. The method is similar to {@link com.microsoft.playwright.Route#resume
|
||||
* Route.resume()} with the difference that other matching handlers will be invoked before sending the request.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* registered route can always override all the previous ones. In the example below, request will be handled by the
|
||||
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
|
||||
* registered route.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs last.
|
||||
@@ -442,18 +472,24 @@ public interface Route {
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Use {@link com.microsoft.playwright.Route#resume Route.resume()} to immediately send the request to the network, other
|
||||
* matching handlers won't be invoked in that case.
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
default void fallback() {
|
||||
fallback(null);
|
||||
}
|
||||
/**
|
||||
* When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* Continues route's request with optional overrides. The method is similar to {@link com.microsoft.playwright.Route#resume
|
||||
* Route.resume()} with the difference that other matching handlers will be invoked before sending the request.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* registered route can always override all the previous ones. In the example below, request will be handled by the
|
||||
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
|
||||
* registered route.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs last.
|
||||
@@ -507,6 +543,9 @@ public interface Route {
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Use {@link com.microsoft.playwright.Route#resume Route.resume()} to immediately send the request to the network, other
|
||||
* matching handlers won't be invoked in that case.
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
void fallback(FallbackOptions options);
|
||||
|
||||
@@ -20,6 +20,9 @@ package com.microsoft.playwright;
|
||||
/**
|
||||
* 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 initialized with {@code hasTouch} set to true.
|
||||
*
|
||||
* <p> This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching touch
|
||||
* events, see the <a href="https://playwright.dev/java/docs/touch-events">emulating legacy touch events</a> page.
|
||||
*/
|
||||
public interface Touchscreen {
|
||||
/**
|
||||
@@ -28,6 +31,8 @@ public interface Touchscreen {
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser
|
||||
* context is false.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void tap(double x, double y);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
@@ -39,8 +40,8 @@ public interface Tracing {
|
||||
class StartOptions {
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify the
|
||||
* final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* Tracing.stop()} instead.
|
||||
*/
|
||||
public String name;
|
||||
@@ -69,8 +70,8 @@ public interface Tracing {
|
||||
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify the
|
||||
* final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* Tracing.stop()} instead.
|
||||
*/
|
||||
public StartOptions setName(String name) {
|
||||
@@ -115,8 +116,8 @@ public interface Tracing {
|
||||
class StartChunkOptions {
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify the
|
||||
* final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public String name;
|
||||
@@ -127,8 +128,8 @@ public interface Tracing {
|
||||
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify the
|
||||
* final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public StartChunkOptions setName(String name) {
|
||||
@@ -143,6 +144,29 @@ public interface Tracing {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GroupOptions {
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public Location location;
|
||||
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public GroupOptions setLocation(String file) {
|
||||
return setLocation(new Location(file));
|
||||
}
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public GroupOptions setLocation(Location location) {
|
||||
this.location = location;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StopOptions {
|
||||
/**
|
||||
* Export trace into the file with the given path.
|
||||
@@ -271,6 +295,56 @@ public interface Tracing {
|
||||
* @since v1.15
|
||||
*/
|
||||
void startChunk(StartChunkOptions options);
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use {@code test.step} instead when available.
|
||||
*
|
||||
* <p> Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link
|
||||
* com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the
|
||||
* trace viewer.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // All actions between group and groupEnd
|
||||
* // will be shown in the trace viewer as a group.
|
||||
* page.context().tracing().group("Open Playwright.dev > API");
|
||||
* page.navigate("https://playwright.dev/");
|
||||
* page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
|
||||
* page.context().tracing().groupEnd();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Group name shown in the trace viewer.
|
||||
* @since v1.49
|
||||
*/
|
||||
default void group(String name) {
|
||||
group(name, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use {@code test.step} instead when available.
|
||||
*
|
||||
* <p> Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link
|
||||
* com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the
|
||||
* trace viewer.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // All actions between group and groupEnd
|
||||
* // will be shown in the trace viewer as a group.
|
||||
* page.context().tracing().group("Open Playwright.dev > API");
|
||||
* page.navigate("https://playwright.dev/");
|
||||
* page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
|
||||
* page.context().tracing().groupEnd();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Group name shown in the trace viewer.
|
||||
* @since v1.49
|
||||
*/
|
||||
void group(String name, GroupOptions options);
|
||||
/**
|
||||
* Closes the last group created by {@link com.microsoft.playwright.Tracing#group Tracing.group()}.
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
void groupEnd();
|
||||
/**
|
||||
* Stop tracing.
|
||||
*
|
||||
|
||||
@@ -20,7 +20,10 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The {@code WebSocket} class represents websocket connections in the page.
|
||||
* The {@code WebSocket} class represents WebSocket connections within a page. It provides the ability to inspect and
|
||||
* manipulate the data being transmitted and received.
|
||||
*
|
||||
* <p> If you want to intercept or modify WebSocket frames, consider using {@code WebSocketRoute}.
|
||||
*/
|
||||
public interface WebSocket {
|
||||
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Whenever a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket">{@code WebSocket}</a> route is set up
|
||||
* with {@link com.microsoft.playwright.Page#routeWebSocket Page.routeWebSocket()} or {@link
|
||||
* com.microsoft.playwright.BrowserContext#routeWebSocket BrowserContext.routeWebSocket()}, the {@code WebSocketRoute}
|
||||
* object allows to handle the WebSocket, like an actual server would do.
|
||||
*
|
||||
* <p> <strong>Mocking</strong>
|
||||
*
|
||||
* <p> By default, the routed WebSocket will not connect to the server. This way, you can mock entire communcation over the
|
||||
* WebSocket. Here is an example that responds to a {@code "request"} with a {@code "response"}.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("wss://example.com/ws", ws -> {
|
||||
* ws.onMessage(frame -> {
|
||||
* if ("request".equals(frame.text()))
|
||||
* ws.send("response");
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Since we do not call {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}
|
||||
* inside the WebSocket route handler, Playwright assumes that WebSocket will be mocked, and opens the WebSocket inside the
|
||||
* page automatically.
|
||||
*
|
||||
* <p> Here is another example that handles JSON messages:
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("wss://example.com/ws", ws -> {
|
||||
* ws.onMessage(frame -> {
|
||||
* JsonObject json = new JsonParser().parse(frame.text()).getAsJsonObject();
|
||||
* if ("question".equals(json.get("request").getAsString())) {
|
||||
* Map<String, String> result = new HashMap();
|
||||
* result.put("response", "answer");
|
||||
* ws.send(gson.toJson(result));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Intercepting</strong>
|
||||
*
|
||||
* <p> Alternatively, you may want to connect to the actual server, but intercept messages in-between and modify or block them.
|
||||
* Calling {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()} returns a
|
||||
* server-side {@code WebSocketRoute} instance that you can send messages to, or handle incoming messages.
|
||||
*
|
||||
* <p> Below is an example that modifies some messages sent by the page to the server. Messages sent from the server to the
|
||||
* page are left intact, relying on the default forwarding.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("/ws", ws -> {
|
||||
* WebSocketRoute server = ws.connectToServer();
|
||||
* ws.onMessage(frame -> {
|
||||
* if ("request".equals(frame.text()))
|
||||
* server.send("request2");
|
||||
* else
|
||||
* server.send(frame.text());
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> After connecting to the server, all **messages are forwarded** between the page and the server by default.
|
||||
*
|
||||
* <p> However, if you call {@link com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} on the
|
||||
* original route, messages from the page to the server **will not be forwarded** anymore, but should instead be handled by
|
||||
* the {@code handler}.
|
||||
*
|
||||
* <p> Similarly, calling {@link com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} on the
|
||||
* server-side WebSocket will **stop forwarding messages** from the server to the page, and {@code handler} should take
|
||||
* care of them.
|
||||
*
|
||||
* <p> The following example blocks some messages in both directions. Since it calls {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} in both directions, there is no automatic
|
||||
* forwarding at all.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("/ws", ws -> {
|
||||
* WebSocketRoute server = ws.connectToServer();
|
||||
* ws.onMessage(frame -> {
|
||||
* if (!"blocked-from-the-page".equals(frame.text()))
|
||||
* server.send(frame.text());
|
||||
* });
|
||||
* server.onMessage(frame -> {
|
||||
* if (!"blocked-from-the-server".equals(frame.text()))
|
||||
* ws.send(frame.text());
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*/
|
||||
public interface WebSocketRoute {
|
||||
class CloseOptions {
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a>.
|
||||
*/
|
||||
public Integer code;
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
*/
|
||||
public String reason;
|
||||
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a>.
|
||||
*/
|
||||
public CloseOptions setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
*/
|
||||
public CloseOptions setReason(String reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Closes one side of the WebSocket connection.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
default void close() {
|
||||
close(null);
|
||||
}
|
||||
/**
|
||||
* Closes one side of the WebSocket connection.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
void close(CloseOptions options);
|
||||
/**
|
||||
* By default, routed WebSocket does not connect to the server, so you can mock entire WebSocket communication. This method
|
||||
* connects to the actual WebSocket server, and returns the server-side {@code WebSocketRoute} instance, giving the ability
|
||||
* to send and receive messages from the server.
|
||||
*
|
||||
* <p> Once connected to the server:
|
||||
* <ul>
|
||||
* <li> Messages received from the server will be **automatically forwarded** to the WebSocket in the page, unless {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} is called on the server-side {@code
|
||||
* WebSocketRoute}.</li>
|
||||
* <li> Messages sent by the <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send">{@code
|
||||
* WebSocket.send()}</a> call in the page will be **automatically forwarded** to the server, unless {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} is called on the original {@code
|
||||
* WebSocketRoute}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> See examples at the top for more details.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
WebSocketRoute connectToServer();
|
||||
/**
|
||||
* Allows to handle <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close">{@code WebSocket.close}</a>.
|
||||
*
|
||||
* <p> By default, closing one side of the connection, either in the page or on the server, will close the other side. However,
|
||||
* when {@link com.microsoft.playwright.WebSocketRoute#onClose WebSocketRoute.onClose()} handler is set up, the default
|
||||
* forwarding of closure is disabled, and handler should take care of it.
|
||||
*
|
||||
* @param handler Function that will handle WebSocket closure. Received an optional <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a> and an optional <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
* @since v1.48
|
||||
*/
|
||||
void onClose(BiConsumer<Integer, String> handler);
|
||||
/**
|
||||
* This method allows to handle messages that are sent by the WebSocket, either from the page or from the server.
|
||||
*
|
||||
* <p> When called on the original WebSocket route, this method handles messages sent from the page. You can handle this
|
||||
* messages by responding to them with {@link com.microsoft.playwright.WebSocketRoute#send WebSocketRoute.send()},
|
||||
* forwarding them to the server-side connection returned by {@link com.microsoft.playwright.WebSocketRoute#connectToServer
|
||||
* WebSocketRoute.connectToServer()} or do something else.
|
||||
*
|
||||
* <p> Once this method is called, messages are not automatically forwarded to the server or to the page - you should do that
|
||||
* manually by calling {@link com.microsoft.playwright.WebSocketRoute#send WebSocketRoute.send()}. See examples at the top
|
||||
* for more details.
|
||||
*
|
||||
* <p> Calling this method again will override the handler with a new one.
|
||||
*
|
||||
* @param handler Function that will handle messages.
|
||||
* @since v1.48
|
||||
*/
|
||||
void onMessage(Consumer<WebSocketFrame> handler);
|
||||
/**
|
||||
* Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called on
|
||||
* the result of {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}, sends
|
||||
* the message to the server. See examples at the top for more details.
|
||||
*
|
||||
* @param message Message to send.
|
||||
* @since v1.48
|
||||
*/
|
||||
void send(String message);
|
||||
/**
|
||||
* Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called on
|
||||
* the result of {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}, sends
|
||||
* the message to the server. See examples at the top for more details.
|
||||
*
|
||||
* @param message Message to send.
|
||||
* @since v1.48
|
||||
*/
|
||||
void send(byte[] message);
|
||||
/**
|
||||
* URL of the WebSocket created in the page.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
+4
-4
@@ -21,15 +21,15 @@ package com.microsoft.playwright.assertions;
|
||||
* The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code
|
||||
* APIResponse} in the tests.
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestPage {
|
||||
* ...
|
||||
* // ...
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* ...
|
||||
* APIResponse response = page.request().get('https://playwright.dev');
|
||||
* // ...
|
||||
* APIResponse response = page.request().get("https://playwright.dev");
|
||||
* assertThat(response).isOK();
|
||||
* }
|
||||
* }
|
||||
|
||||
+334
-47
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
@@ -23,14 +24,14 @@ import com.microsoft.playwright.options.AriaRole;
|
||||
* The {@code LocatorAssertions} class provides assertion methods that can be used to make assertions about the {@code
|
||||
* Locator} state in the tests.
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestLocator {
|
||||
* ...
|
||||
* // ...
|
||||
* @Test
|
||||
* void statusBecomesSubmitted() {
|
||||
* ...
|
||||
* // ...
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* assertThat(page.locator(".status")).hasText("Submitted");
|
||||
* }
|
||||
@@ -58,16 +59,37 @@ public interface LocatorAssertions {
|
||||
}
|
||||
}
|
||||
class IsCheckedOptions {
|
||||
/**
|
||||
* Provides state to assert for. Asserts for input to be checked by default. This option can't be used when {@code
|
||||
* indeterminate} is set to true.
|
||||
*/
|
||||
public Boolean checked;
|
||||
/**
|
||||
* Asserts that the element is in the indeterminate (mixed) state. Only supported for checkboxes and radio buttons. This
|
||||
* option can't be true when {@code checked} is provided.
|
||||
*/
|
||||
public Boolean indeterminate;
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Provides state to assert for. Asserts for input to be checked by default. This option can't be used when {@code
|
||||
* indeterminate} is set to true.
|
||||
*/
|
||||
public IsCheckedOptions setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Asserts that the element is in the indeterminate (mixed) state. Only supported for checkboxes and radio buttons. This
|
||||
* option can't be true when {@code checked} is provided.
|
||||
*/
|
||||
public IsCheckedOptions setIndeterminate(boolean indeterminate) {
|
||||
this.indeterminate = indeterminate;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
@@ -216,6 +238,20 @@ public interface LocatorAssertions {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ContainsClassOptions {
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public ContainsClassOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ContainsTextOptions {
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
@@ -281,6 +317,33 @@ public interface LocatorAssertions {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HasAccessibleErrorMessageOptions {
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression flag if specified.
|
||||
*/
|
||||
public Boolean ignoreCase;
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression flag if specified.
|
||||
*/
|
||||
public HasAccessibleErrorMessageOptions setIgnoreCase(boolean ignoreCase) {
|
||||
this.ignoreCase = ignoreCase;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public HasAccessibleErrorMessageOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HasAccessibleNameOptions {
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
@@ -485,6 +548,20 @@ public interface LocatorAssertions {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class MatchesAriaSnapshotOptions {
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public MatchesAriaSnapshotOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Makes the assertion check for the opposite condition. For example, this code tests that the Locator doesn't contain text
|
||||
* {@code "error"}:
|
||||
@@ -793,6 +870,98 @@ public interface LocatorAssertions {
|
||||
* @since v1.20
|
||||
*/
|
||||
void isVisible(IsVisibleOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
|
||||
* by spaces, must be present in the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList">Element.classList</a> in any order.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).containsClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).containsClass("selected");
|
||||
* assertThat(page.locator("#component")).containsClass("row middle");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class lists. Each element's class attribute is matched against the corresponding class in the array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
|
||||
* @since v1.52
|
||||
*/
|
||||
default void containsClass(String expected) {
|
||||
containsClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
|
||||
* by spaces, must be present in the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList">Element.classList</a> in any order.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).containsClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).containsClass("selected");
|
||||
* assertThat(page.locator("#component")).containsClass("row middle");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class lists. Each element's class attribute is matched against the corresponding class in the array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
|
||||
* @since v1.52
|
||||
*/
|
||||
void containsClass(String expected, ContainsClassOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
|
||||
* by spaces, must be present in the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList">Element.classList</a> in any order.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).containsClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).containsClass("selected");
|
||||
* assertThat(page.locator("#component")).containsClass("row middle");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class lists. Each element's class attribute is matched against the corresponding class in the array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
|
||||
* @since v1.52
|
||||
*/
|
||||
default void containsClass(List<String> expected) {
|
||||
containsClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
|
||||
* by spaces, must be present in the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/Element/classList">Element.classList</a> in any order.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).containsClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).containsClass("selected");
|
||||
* assertThat(page.locator("#component")).containsClass("row middle");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class lists. Each element's class attribute is matched against the corresponding class in the array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
|
||||
* @since v1.52
|
||||
*/
|
||||
void containsClass(List<String> expected, ContainsClassOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element that contains the given text. All nested elements will be considered
|
||||
* when computing the text content of the element. You can use regular expressions for the value as well.
|
||||
@@ -1205,6 +1374,66 @@ public interface LocatorAssertions {
|
||||
* @since v1.44
|
||||
*/
|
||||
void hasAccessibleDescription(Pattern description, HasAccessibleDescriptionOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with a given <a
|
||||
* href="https://w3c.github.io/aria/#aria-errormessage">aria errormessage</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator locator = page.getByTestId("username-input");
|
||||
* assertThat(locator).hasAccessibleErrorMessage("Username is required.");
|
||||
* }</pre>
|
||||
*
|
||||
* @param errorMessage Expected accessible error message.
|
||||
* @since v1.50
|
||||
*/
|
||||
default void hasAccessibleErrorMessage(String errorMessage) {
|
||||
hasAccessibleErrorMessage(errorMessage, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with a given <a
|
||||
* href="https://w3c.github.io/aria/#aria-errormessage">aria errormessage</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator locator = page.getByTestId("username-input");
|
||||
* assertThat(locator).hasAccessibleErrorMessage("Username is required.");
|
||||
* }</pre>
|
||||
*
|
||||
* @param errorMessage Expected accessible error message.
|
||||
* @since v1.50
|
||||
*/
|
||||
void hasAccessibleErrorMessage(String errorMessage, HasAccessibleErrorMessageOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with a given <a
|
||||
* href="https://w3c.github.io/aria/#aria-errormessage">aria errormessage</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator locator = page.getByTestId("username-input");
|
||||
* assertThat(locator).hasAccessibleErrorMessage("Username is required.");
|
||||
* }</pre>
|
||||
*
|
||||
* @param errorMessage Expected accessible error message.
|
||||
* @since v1.50
|
||||
*/
|
||||
default void hasAccessibleErrorMessage(Pattern errorMessage) {
|
||||
hasAccessibleErrorMessage(errorMessage, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with a given <a
|
||||
* href="https://w3c.github.io/aria/#aria-errormessage">aria errormessage</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator locator = page.getByTestId("username-input");
|
||||
* assertThat(locator).hasAccessibleErrorMessage("Username is required.");
|
||||
* }</pre>
|
||||
*
|
||||
* @param errorMessage Expected accessible error message.
|
||||
* @since v1.50
|
||||
*/
|
||||
void hasAccessibleErrorMessage(Pattern errorMessage, HasAccessibleErrorMessageOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with a given <a
|
||||
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
|
||||
@@ -1322,16 +1551,19 @@ public interface LocatorAssertions {
|
||||
*/
|
||||
void hasAttribute(String name, Pattern value, HasAttributeOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1343,16 +1575,19 @@ public interface LocatorAssertions {
|
||||
hasClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1362,16 +1597,19 @@ public interface LocatorAssertions {
|
||||
*/
|
||||
void hasClass(String expected, HasClassOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1383,16 +1621,19 @@ public interface LocatorAssertions {
|
||||
hasClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1402,16 +1643,19 @@ public interface LocatorAssertions {
|
||||
*/
|
||||
void hasClass(Pattern expected, HasClassOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1423,16 +1667,19 @@ public interface LocatorAssertions {
|
||||
hasClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1442,16 +1689,19 @@ public interface LocatorAssertions {
|
||||
*/
|
||||
void hasClass(String[] expected, HasClassOptions options);
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -1463,16 +1713,19 @@ public interface LocatorAssertions {
|
||||
hasClass(expected, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. This needs to be a full match or using a
|
||||
* relaxed regular expression.
|
||||
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
|
||||
* the element's {@code class} attribute. To match individual classes use {@link
|
||||
* com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("selected"));
|
||||
* assertThat(page.locator("#component")).hasClass("selected row");
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Note that if array is passed as an expected value, entire lists of elements can be asserted:
|
||||
* <p> When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
|
||||
* class values. Each element's class attribute is matched against the corresponding string or regular expression in the
|
||||
* array:
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
@@ -2097,7 +2350,7 @@ public interface LocatorAssertions {
|
||||
*
|
||||
* <p> For example, given the following element:
|
||||
* <pre>{@code
|
||||
* page.locator("id=favorite-colors").selectOption(["R", "G"]);
|
||||
* page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
|
||||
* assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
|
||||
* }</pre>
|
||||
*
|
||||
@@ -2115,7 +2368,7 @@ public interface LocatorAssertions {
|
||||
*
|
||||
* <p> For example, given the following element:
|
||||
* <pre>{@code
|
||||
* page.locator("id=favorite-colors").selectOption(["R", "G"]);
|
||||
* page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
|
||||
* assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
|
||||
* }</pre>
|
||||
*
|
||||
@@ -2131,7 +2384,7 @@ public interface LocatorAssertions {
|
||||
*
|
||||
* <p> For example, given the following element:
|
||||
* <pre>{@code
|
||||
* page.locator("id=favorite-colors").selectOption(["R", "G"]);
|
||||
* page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
|
||||
* assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
|
||||
* }</pre>
|
||||
*
|
||||
@@ -2149,7 +2402,7 @@ public interface LocatorAssertions {
|
||||
*
|
||||
* <p> For example, given the following element:
|
||||
* <pre>{@code
|
||||
* page.locator("id=favorite-colors").selectOption(["R", "G"]);
|
||||
* page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
|
||||
* assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
|
||||
* }</pre>
|
||||
*
|
||||
@@ -2157,5 +2410,39 @@ public interface LocatorAssertions {
|
||||
* @since v1.23
|
||||
*/
|
||||
void hasValues(Pattern[] values, HasValuesOptions options);
|
||||
/**
|
||||
* Asserts that the target element matches the given <a
|
||||
* href="https://playwright.dev/java/docs/aria-snapshots">accessibility snapshot</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.navigate("https://demo.playwright.dev/todomvc/");
|
||||
* assertThat(page.locator("body")).matchesAriaSnapshot("""
|
||||
* - heading "todos"
|
||||
* - textbox "What needs to be done?"
|
||||
* """);
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
default void matchesAriaSnapshot(String expected) {
|
||||
matchesAriaSnapshot(expected, null);
|
||||
}
|
||||
/**
|
||||
* Asserts that the target element matches the given <a
|
||||
* href="https://playwright.dev/java/docs/aria-snapshots">accessibility snapshot</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.navigate("https://demo.playwright.dev/todomvc/");
|
||||
* assertThat(page.locator("body")).matchesAriaSnapshot("""
|
||||
* - heading "todos"
|
||||
* - textbox "What needs to be done?"
|
||||
* """);
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions options);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ import java.util.regex.Pattern;
|
||||
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page}
|
||||
* state in the tests.
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* // ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestPage {
|
||||
* ...
|
||||
* // ...
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* ...
|
||||
* // ...
|
||||
* page.getByText("Sign in").click();
|
||||
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
|
||||
* }
|
||||
@@ -54,7 +54,7 @@ public interface PageAssertions {
|
||||
class HasURLOptions {
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression flag if specified.
|
||||
* expression parameter if specified. A provided predicate ignores this flag.
|
||||
*/
|
||||
public Boolean ignoreCase;
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ public interface PageAssertions {
|
||||
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression flag if specified.
|
||||
* expression parameter if specified. A provided predicate ignores this flag.
|
||||
*/
|
||||
public HasURLOptions setIgnoreCase(boolean ignoreCase) {
|
||||
this.ignoreCase = ignoreCase;
|
||||
|
||||
+2
-3
@@ -30,14 +30,13 @@ import com.microsoft.playwright.impl.PageAssertionsImpl;
|
||||
*
|
||||
* <p> Consider the following example:
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestExample {
|
||||
* ...
|
||||
* // ...
|
||||
* @Test
|
||||
* void statusBecomesSubmitted() {
|
||||
* ...
|
||||
* // ...
|
||||
* page.locator("#submit-button").click();
|
||||
* assertThat(page.locator(".status")).hasText("Submitted");
|
||||
* }
|
||||
|
||||
@@ -147,6 +147,12 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
}
|
||||
params.addProperty("maxRedirects", options.maxRedirects);
|
||||
}
|
||||
if (options.maxRetries != null) {
|
||||
if (options.maxRetries < 0) {
|
||||
throw new PlaywrightException("'maxRetries' must be greater than or equal to '0'");
|
||||
}
|
||||
params.addProperty("maxRetries", options.maxRetries);
|
||||
}
|
||||
JsonObject json = sendMessage("fetch", params).getAsJsonObject();
|
||||
return new APIResponseImpl(this, json.getAsJsonObject("response"));
|
||||
}
|
||||
|
||||
@@ -17,15 +17,21 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.APIRequest;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.ClientCertificate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.addToProtocol;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
|
||||
class APIRequestImpl implements APIRequest {
|
||||
private final PlaywrightImpl playwright;
|
||||
@@ -42,6 +48,8 @@ class APIRequestImpl implements APIRequest {
|
||||
private APIRequestContextImpl newContextImpl(NewContextOptions options) {
|
||||
if (options == null) {
|
||||
options = new NewContextOptions();
|
||||
} else {
|
||||
options = Utils.clone(options);
|
||||
}
|
||||
if (options.storageStatePath != null) {
|
||||
try {
|
||||
@@ -57,11 +65,13 @@ class APIRequestImpl implements APIRequest {
|
||||
storageState = new Gson().fromJson(options.storageState, JsonObject.class);
|
||||
options.storageState = null;
|
||||
}
|
||||
List<ClientCertificate> clientCertificateList = options.clientCertificates;
|
||||
options.clientCertificates = null;
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (storageState != null) {
|
||||
params.add("storageState", storageState);
|
||||
}
|
||||
|
||||
addToProtocol(params, clientCertificateList);
|
||||
JsonObject result = playwright.sendMessage("newRequest", params).getAsJsonObject();
|
||||
APIRequestContextImpl context = playwright.connection.getExistingObject(result.getAsJsonObject("request").get("guid").getAsString());
|
||||
return context;
|
||||
|
||||
@@ -46,22 +46,20 @@ class APIResponseImpl implements APIResponse {
|
||||
|
||||
@Override
|
||||
public byte[] body() {
|
||||
return context.withLogging("APIResponse.body", () -> {
|
||||
try {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchResponseBody", params).getAsJsonObject();
|
||||
if (!json.has("binary")) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
if (isSafeCloseError(e)) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
throw e;
|
||||
try {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchResponseBody", params).getAsJsonObject();
|
||||
if (!json.has("binary")) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
});
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
if (isSafeCloseError(e)) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,7 +47,6 @@ class AssertionsBase {
|
||||
options = new FrameExpectOptions();
|
||||
}
|
||||
options.expectedText = expectedText;
|
||||
options.isNot = isNot;
|
||||
expectImpl(expression, options, expected, message);
|
||||
}
|
||||
|
||||
@@ -55,13 +54,14 @@ class AssertionsBase {
|
||||
if (expectOptions.timeout == null) {
|
||||
expectOptions.timeout = AssertionsTimeout.defaultTimeout;
|
||||
}
|
||||
if (expectOptions.isNot) {
|
||||
expectOptions.isNot = isNot;
|
||||
if (isNot) {
|
||||
message = message.replace("expected to", "expected not to");
|
||||
}
|
||||
FrameExpectResult result = actualLocator.expect(expression, expectOptions);
|
||||
if (result.matches == isNot) {
|
||||
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
|
||||
String log = String.join("\n", result.log);
|
||||
String log = (result.log == null) ? "" : String.join("\n", result.log);
|
||||
if (!log.isEmpty()) {
|
||||
log = "\nCall log:\n" + log;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
final List<PageImpl> backgroundPages = new ArrayList<>();
|
||||
|
||||
final Router routes = new Router();
|
||||
final WebSocketRouter webSocketRoutes = new WebSocketRouter();
|
||||
private boolean closeWasCalled;
|
||||
private final WaitableEvent<EventType, ?> closePromise;
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
@@ -479,7 +480,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void route(String url, Consumer<Route> handler, RouteOptions options) {
|
||||
route(new UrlMatcher(baseUrl, url), handler, options);
|
||||
route(UrlMatcher.forGlob(baseUrl, url, this.connection.localUtils, false), handler, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -501,7 +502,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
recordIntoHar(null, har, options);
|
||||
return;
|
||||
}
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(baseUrl, options.url);
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(baseUrl, options.url, this.connection.localUtils, false);
|
||||
HARRouter harRouter = new HARRouter(connection.localUtils, har, options.notFound);
|
||||
onClose(context -> harRouter.dispose());
|
||||
route(matcher, route -> harRouter.handle(route), null);
|
||||
@@ -514,6 +515,28 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(String url, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(UrlMatcher.forGlob(baseUrl, url, this.connection.localUtils, true), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(Pattern pattern, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(new UrlMatcher(pattern), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(Predicate<String> predicate, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(new UrlMatcher(predicate), handler);
|
||||
}
|
||||
|
||||
private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
withLogging("BrowserContext.routeWebSocket", () -> {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (page != null) {
|
||||
@@ -600,14 +623,22 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public String storageState(StorageStateOptions options) {
|
||||
return withLogging("BrowserContext.storageState", () -> {
|
||||
JsonElement json = sendMessage("storageState");
|
||||
String storageState = json.toString();
|
||||
if (options != null && options.path != null) {
|
||||
Utils.writeToFile(storageState.getBytes(StandardCharsets.UTF_8), options.path);
|
||||
}
|
||||
return storageState;
|
||||
});
|
||||
return withLogging("BrowserContext.storageState", () -> storageStateImpl(options));
|
||||
}
|
||||
|
||||
private String storageStateImpl(StorageStateOptions options) {
|
||||
if (options == null) {
|
||||
options = new StorageStateOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.remove("path");
|
||||
JsonElement json = sendMessage("storageState", params);
|
||||
|
||||
String storageState = json.toString();
|
||||
if (options.path != null) {
|
||||
Utils.writeToFile(storageState.getBytes(StandardCharsets.UTF_8), options.path);
|
||||
}
|
||||
return storageState;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -625,7 +656,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(new UrlMatcher(this.baseUrl, url), handler);
|
||||
unroute(UrlMatcher.forGlob(this.baseUrl, url, this.connection.localUtils, false), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -681,6 +712,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
}
|
||||
|
||||
private void updateWebSocketInterceptionPatterns() {
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns());
|
||||
}
|
||||
|
||||
void handleRoute(RouteImpl route) {
|
||||
Router.HandleResult handled = routes.handle(route);
|
||||
if (handled != Router.HandleResult.NoMatchingHandler) {
|
||||
@@ -691,6 +726,12 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
void handleWebSocketRoute(WebSocketRouteImpl route) {
|
||||
if (!webSocketRoutes.handle(route)) {
|
||||
route.connectToServer();
|
||||
}
|
||||
}
|
||||
|
||||
WaitableResult<JsonElement> pause() {
|
||||
return sendMessageAsync("pause", new JsonObject());
|
||||
}
|
||||
@@ -730,6 +771,9 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
RouteImpl route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
|
||||
route.browserContext = this;
|
||||
handleRoute(route);
|
||||
} else if ("webSocketRoute".equals(event)) {
|
||||
WebSocketRouteImpl route = connection.getExistingObject(params.getAsJsonObject("webSocketRoute").get("guid").getAsString());
|
||||
handleWebSocketRoute(route);
|
||||
} else if ("page".equals(event)) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
pages.add(page);
|
||||
|
||||
@@ -208,6 +208,7 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
params.addProperty("noDefaultViewport", true);
|
||||
}
|
||||
}
|
||||
addToProtocol(params, options.clientCertificates);
|
||||
params.remove("acceptDownloads");
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
|
||||
@@ -26,10 +26,12 @@ import com.microsoft.playwright.options.HarContentPolicy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.addHarUrlFilter;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.addToProtocol;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
@@ -195,6 +197,10 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
}
|
||||
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (!userDataDir.isAbsolute() && !userDataDir.toString().isEmpty()) {
|
||||
Path cwd = Paths.get("").toAbsolutePath();
|
||||
userDataDir = cwd.resolve(userDataDir);
|
||||
}
|
||||
params.addProperty("userDataDir", userDataDir.toString());
|
||||
if (recordHar != null) {
|
||||
params.add("recordHar", recordHar);
|
||||
@@ -221,6 +227,7 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
params.addProperty("noDefaultViewport", true);
|
||||
}
|
||||
}
|
||||
addToProtocol(params, options.clientCertificates);
|
||||
params.remove("acceptDownloads");
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
|
||||
@@ -35,6 +35,7 @@ class ChannelOwner extends LoggingSupport {
|
||||
final String guid;
|
||||
final JsonObject initializer;
|
||||
private boolean wasCollected;
|
||||
private boolean isInternalType;
|
||||
|
||||
protected ChannelOwner(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
this(parent.connection, parent, type, guid, initializer);
|
||||
@@ -58,6 +59,10 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
}
|
||||
|
||||
void markAsInternalType() {
|
||||
isInternalType = true;
|
||||
}
|
||||
|
||||
void disposeChannelOwner(boolean wasGarbageCollected) {
|
||||
// Clean up from parent and connection.
|
||||
if (parent != null) {
|
||||
@@ -84,6 +89,9 @@ class ChannelOwner extends LoggingSupport {
|
||||
|
||||
@Override
|
||||
<T> T withLogging(String apiName, Supplier<T> code) {
|
||||
if (isInternalType) {
|
||||
apiName = null;
|
||||
}
|
||||
String previousApiName = connection.setApiName(apiName);
|
||||
try {
|
||||
return super.withLogging(apiName, code);
|
||||
@@ -92,6 +100,10 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
}
|
||||
|
||||
WaitableResult<JsonElement> sendMessageAsync(String method) {
|
||||
return sendMessageAsync(method, new JsonObject());
|
||||
}
|
||||
|
||||
WaitableResult<JsonElement> sendMessageAsync(String method, JsonObject params) {
|
||||
checkNotCollected();
|
||||
return connection.sendMessageAsync(guid, method, params);
|
||||
|
||||
@@ -12,18 +12,24 @@ class ClockImpl implements Clock {
|
||||
this.browserContext = browserContext;
|
||||
}
|
||||
|
||||
private void sendMessageWithLogging(String method, JsonObject params) {
|
||||
String capitalizedMethod = method.substring(0, 1).toUpperCase() + method.substring(1);
|
||||
browserContext.withLogging("Clock." + method,
|
||||
() -> browserContext.sendMessage("clock" + capitalizedMethod, params));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastForward(long ticks) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("ticksNumber", ticks);
|
||||
browserContext.sendMessage("clockFastForward", params);
|
||||
sendMessageWithLogging("fastForward", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fastForward(String ticks) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("ticksString", ticks);
|
||||
browserContext.sendMessage("clockFastForward", params);
|
||||
sendMessageWithLogging("fastForward", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,89 +38,89 @@ class ClockImpl implements Clock {
|
||||
if (options != null) {
|
||||
parseTime(options.time, params);
|
||||
}
|
||||
browserContext.sendMessage("clockInstall", params);
|
||||
sendMessageWithLogging("install", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runFor(long ticks) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("ticksNumber", ticks);
|
||||
browserContext.sendMessage("clockRunFor", params);
|
||||
sendMessageWithLogging("runFor", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runFor(String ticks) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("ticksString", ticks);
|
||||
browserContext.sendMessage("clockRunFor", params);
|
||||
sendMessageWithLogging("runFor", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pauseAt(long time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time);
|
||||
browserContext.sendMessage("clockPauseAt", params);
|
||||
sendMessageWithLogging("pauseAt", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pauseAt(String time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeString", time);
|
||||
browserContext.sendMessage("clockPauseAt", params);
|
||||
sendMessageWithLogging("pauseAt", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pauseAt(Date time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time.getTime());
|
||||
browserContext.sendMessage("clockPauseAt", params);
|
||||
sendMessageWithLogging("pauseAt", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
browserContext.sendMessage("clockResume");
|
||||
sendMessageWithLogging("resume", new JsonObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFixedTime(long time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time);
|
||||
browserContext.sendMessage("clockSetFixedTime", params);
|
||||
sendMessageWithLogging("setFixedTime", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFixedTime(String time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeString", time);
|
||||
browserContext.sendMessage("clockSetFixedTime", params);
|
||||
sendMessageWithLogging("setFixedTime", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFixedTime(Date time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time.getTime());
|
||||
browserContext.sendMessage("clockSetFixedTime", params);
|
||||
sendMessageWithLogging("setFixedTime", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemTime(long time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time);
|
||||
browserContext.sendMessage("clockSetSystemTime", params);
|
||||
sendMessageWithLogging("setSystemTime", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemTime(String time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeString", time);
|
||||
browserContext.sendMessage("clockSetSystemTime", params);
|
||||
sendMessageWithLogging("setSystemTime", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemTime(Date time) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeNumber", time.getTime());
|
||||
browserContext.sendMessage("clockSetSystemTime", params);
|
||||
sendMessageWithLogging("setSystemTime", params);
|
||||
}
|
||||
|
||||
private static void parseTime(Object time, JsonObject params) {
|
||||
|
||||
@@ -384,6 +384,9 @@ public class Connection {
|
||||
case "WebSocket":
|
||||
result = new WebSocketImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "WebSocketRoute":
|
||||
result = new WebSocketRouteImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Worker":
|
||||
result = new WorkerImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
|
||||
@@ -1031,7 +1031,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
List<Waitable<Response>> waitables = new ArrayList<>();
|
||||
if (matcher == null) {
|
||||
matcher = UrlMatcher.forOneOf(page.context().baseUrl, options.url);
|
||||
matcher = UrlMatcher.forOneOf(page.context().baseUrl, options.url, this.connection.localUtils, false);
|
||||
}
|
||||
logger.log("waiting for navigation " + matcher);
|
||||
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil, logger));
|
||||
@@ -1078,7 +1078,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(page.context().baseUrl, url), options);
|
||||
waitForURL(UrlMatcher.forGlob(page.context().baseUrl, url, this.connection.localUtils, false), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -136,6 +136,6 @@ class FrameLocatorImpl implements FrameLocator {
|
||||
|
||||
@Override
|
||||
public Locator owner() {
|
||||
return new LocatorImpl(frame, frameSelector);
|
||||
return new LocatorImpl(frame, frameSelector, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
@@ -46,6 +47,9 @@ class ListenerCollection <EventType> {
|
||||
}
|
||||
|
||||
void add(EventType type, Consumer<?> listener) {
|
||||
if (listener == null) {
|
||||
throw new PlaywrightException("Can't add a null listener");
|
||||
}
|
||||
List<Consumer<?>> list = listeners.get(type);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
|
||||
@@ -21,12 +21,14 @@ import com.google.gson.JsonObject;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class LocalUtils extends ChannelOwner {
|
||||
public class LocalUtils extends ChannelOwner {
|
||||
LocalUtils(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
}
|
||||
|
||||
JsonArray deviceDescriptors() {
|
||||
@@ -58,4 +60,16 @@ class LocalUtils extends ChannelOwner {
|
||||
JsonObject json = connection.localUtils().sendMessage("tracingStarted", params).getAsJsonObject();
|
||||
return json.get("stacksId").getAsString();
|
||||
}
|
||||
|
||||
public Pattern globToRegex(String glob, String baseURL, boolean webSocketUrl) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("glob", glob);
|
||||
if (baseURL != null) {
|
||||
params.addProperty("baseURL", baseURL);
|
||||
}
|
||||
params.addProperty("webSocketUrl", webSocketUrl);
|
||||
JsonObject json = connection.localUtils().sendMessage("globToRegex", params).getAsJsonObject();
|
||||
String regex = json.get("regex").getAsString();
|
||||
return Pattern.compile(regex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.serializeArgument;
|
||||
@@ -37,6 +39,25 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
super((LocatorImpl) locator, isNot);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void containsClass(String classname, ContainsClassOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = classname;
|
||||
expectImpl("to.contain.class", expected, classname, "Locator expected to contain class", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsClass(List<String> classnames, ContainsClassOptions options) {
|
||||
List<ExpectedTextValue> list = new ArrayList<>();
|
||||
for (String text : classnames) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = text;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.contain.class.array", list, classnames, "Locator expected to contain classes", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containsText(String text, ContainsTextOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
@@ -88,6 +109,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = description;
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.description", expected, description, "Locator expected to have accessible description", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@@ -95,14 +117,33 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
public void hasAccessibleDescription(Pattern pattern, HasAccessibleDescriptionOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.description", expected, pattern, "Locator expected to have accessible description", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAccessibleErrorMessage(String errorMessage, HasAccessibleErrorMessageOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = errorMessage;
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.error.message", expected, errorMessage, "Locator expected to have accessible error message", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAccessibleErrorMessage(Pattern pattern, HasAccessibleErrorMessageOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.error.message", expected, pattern, "Locator expected to have accessible error message", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAccessibleName(String name, HasAccessibleNameOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = name;
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.name", expected, name, "Locator expected to have accessible name", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@@ -110,6 +151,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
public void hasAccessibleName(Pattern pattern, HasAccessibleNameOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.accessible.name", expected, pattern, "Locator expected to have accessible name", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@@ -326,12 +368,42 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expectImpl("to.have.values", list, patterns, "Locator expected to have values matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions snapshotOptions) {
|
||||
if (snapshotOptions == null) {
|
||||
snapshotOptions = new MatchesAriaSnapshotOptions();
|
||||
}
|
||||
FrameExpectOptions options = convertType(snapshotOptions, FrameExpectOptions.class);
|
||||
options.expectedValue = serializeArgument(expected);
|
||||
expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isChecked(IsCheckedOptions options) {
|
||||
boolean unchecked = options != null && options.checked != null && !options.checked;
|
||||
String expression = unchecked ? "to.be.unchecked" : "to.be.checked";
|
||||
String message = "Locator expected to be " + (unchecked ? "un" : "") + "checked";
|
||||
expectTrue(expression, message, convertType(options, FrameExpectOptions.class));
|
||||
if (options == null) {
|
||||
options = new IsCheckedOptions();
|
||||
}
|
||||
|
||||
Map<String, Boolean> expectedValue = new HashMap<>();
|
||||
if (options.indeterminate != null) {
|
||||
expectedValue.put("indeterminate", options.indeterminate);
|
||||
}
|
||||
if (options.checked != null) {
|
||||
expectedValue.put("checked", options.checked);
|
||||
}
|
||||
|
||||
String expected;
|
||||
if (options.indeterminate != null && options.indeterminate) {
|
||||
expected = "indeterminate";
|
||||
} else {
|
||||
boolean unchecked = options.checked != null && !options.checked;
|
||||
expected = unchecked ? "unchecked" : "checked";
|
||||
}
|
||||
|
||||
String message = "Locator expected to be";
|
||||
FrameExpectOptions expectOptions = convertType(options, FrameExpectOptions.class);
|
||||
expectOptions.expectedValue = serializeArgument(expectedValue);
|
||||
expectImpl("to.be.checked", expectOptions, expected, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,29 +21,25 @@ import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorUtils.*;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
|
||||
class LocatorImpl implements Locator {
|
||||
final FrameImpl frame;
|
||||
final String selector;
|
||||
|
||||
LocatorImpl(FrameImpl frame, String frameSelector) {
|
||||
this(frame, frameSelector, null);
|
||||
LocatorImpl(FrameImpl frame, String selector, LocatorOptions options) {
|
||||
this(frame, selector, options, null);
|
||||
}
|
||||
|
||||
public LocatorImpl(FrameImpl frame, String selector, LocatorOptions options) {
|
||||
private LocatorImpl(FrameImpl frame, String selector, LocatorOptions options, Boolean visible) {
|
||||
this.frame = frame;
|
||||
if (options != null) {
|
||||
if (options.hasText != null) {
|
||||
@@ -65,6 +61,9 @@ class LocatorImpl implements Locator {
|
||||
selector += " >> internal:has-not=" + gson().toJson(locator.selector);
|
||||
}
|
||||
}
|
||||
if (visible != null) {
|
||||
selector += " >> visible=" + visible;
|
||||
}
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@@ -119,6 +118,21 @@ class LocatorImpl implements Locator {
|
||||
return new LocatorImpl(frame, selector + " >> internal:and=" + gson().toJson(other.selector), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ariaSnapshot(AriaSnapshotOptions options) {
|
||||
return frame.withLogging("Locator.ariaSnapshot", () -> ariaSnapshotImpl(options));
|
||||
}
|
||||
|
||||
private String ariaSnapshotImpl(AriaSnapshotOptions options) {
|
||||
if (options == null) {
|
||||
options = new AriaSnapshotOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject result = frame.sendMessage("ariaSnapshot", params).getAsJsonObject();
|
||||
return result.get("snapshot").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blur(BlurOptions options) {
|
||||
frame.withLogging("Locator.blur", () -> blurImpl(options));
|
||||
@@ -237,7 +251,8 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@Override
|
||||
public Locator filter(FilterOptions options) {
|
||||
return new LocatorImpl(frame, selector, convertType(options,LocatorOptions.class));
|
||||
Boolean visible = (options == null) ? null : options.visible;
|
||||
return new LocatorImpl(frame, selector, convertType(options, LocatorOptions.class), visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -650,9 +665,6 @@ class LocatorImpl implements Locator {
|
||||
}
|
||||
|
||||
private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
|
||||
if (options == null) {
|
||||
options = new FrameExpectOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", expression);
|
||||
|
||||
@@ -48,6 +48,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
final Waitable<?> waitableClosedOrCrashed;
|
||||
private ViewportSize viewport;
|
||||
private final Router routes = new Router();
|
||||
private final WebSocketRouter webSocketRoutes = new WebSocketRouter();
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
private final Map<Integer, LocatorHandler> locatorHandlers = new HashMap<>();
|
||||
|
||||
@@ -212,6 +213,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
|
||||
browserContext.handleRoute(route);
|
||||
}
|
||||
} else if ("webSocketRoute".equals(event)) {
|
||||
WebSocketRouteImpl route = connection.getExistingObject(params.getAsJsonObject("webSocketRoute").get("guid").getAsString());
|
||||
if (!webSocketRoutes.handle(route)) {
|
||||
browserContext.handleWebSocketRoute(route);
|
||||
}
|
||||
} else if ("video".equals(event)) {
|
||||
String artifactGuid = params.getAsJsonObject("artifact").get("guid").getAsString();
|
||||
ArtifactImpl artifact = connection.getExistingObject(artifactGuid);
|
||||
@@ -779,7 +785,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Frame frameByUrl(String glob) {
|
||||
return frameFor(new UrlMatcher(browserContext.baseUrl, glob));
|
||||
return frameFor(UrlMatcher.forGlob(browserContext.baseUrl, glob, this.connection.localUtils, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -927,6 +933,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestGC() {
|
||||
withLogging("Page.requestGC", () -> sendMessage("requestGC"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseImpl navigate(String url, NavigateOptions options) {
|
||||
return withLogging("Page.navigate", () -> mainFrame.navigateImpl(url, convertType(options, Frame.NavigateOptions.class)));
|
||||
@@ -1094,7 +1105,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void route(String url, Consumer<Route> handler, RouteOptions options) {
|
||||
route(new UrlMatcher(browserContext.baseUrl, url), handler, options);
|
||||
route(UrlMatcher.forGlob(browserContext.baseUrl, url, this.connection.localUtils, false), handler, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1116,7 +1127,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
browserContext.recordIntoHar(this, har, convertType(options, BrowserContext.RouteFromHAROptions.class));
|
||||
return;
|
||||
}
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(browserContext.baseUrl, options.url);
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(browserContext.baseUrl, options.url, this.connection.localUtils, false);
|
||||
HARRouter harRouter = new HARRouter(connection.localUtils, har, options.notFound);
|
||||
onClose(context -> harRouter.dispose());
|
||||
route(matcher, route -> harRouter.handle(route), null);
|
||||
@@ -1129,6 +1140,28 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(String url, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(UrlMatcher.forGlob(browserContext.baseUrl, url, this.connection.localUtils, true), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(Pattern pattern, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(new UrlMatcher(pattern), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(Predicate<String> predicate, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(new UrlMatcher(predicate), handler);
|
||||
}
|
||||
|
||||
private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
withLogging("Page.routeWebSocket", () -> {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] screenshot(ScreenshotOptions options) {
|
||||
return withLogging("Page.screenshot", () -> screenshotImpl(options));
|
||||
@@ -1332,7 +1365,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(new UrlMatcher(browserContext.baseUrl, url), handler);
|
||||
unroute(UrlMatcher.forGlob(browserContext.baseUrl, url, this.connection.localUtils, false), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1356,6 +1389,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
}
|
||||
|
||||
private void updateWebSocketInterceptionPatterns() {
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return mainFrame.url();
|
||||
@@ -1471,7 +1508,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Request waitForRequest(String urlGlob, WaitForRequestOptions options, Runnable code) {
|
||||
return waitForRequest(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
|
||||
return waitForRequest(UrlMatcher.forGlob(browserContext.baseUrl, urlGlob, this.connection.localUtils, false), null, options, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1516,7 +1553,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Response waitForResponse(String urlGlob, WaitForResponseOptions options, Runnable code) {
|
||||
return waitForResponse(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
|
||||
return waitForResponse(UrlMatcher.forGlob(browserContext.baseUrl, urlGlob, this.connection.localUtils, false), null, options, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1569,7 +1606,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(browserContext.baseUrl, url), options);
|
||||
waitForURL(UrlMatcher.forGlob(browserContext.baseUrl, url, this.connection.localUtils, false), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -90,8 +90,12 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
sharedSelectors.removeChannel(selectors);
|
||||
}
|
||||
|
||||
public LocalUtils localUtils() {
|
||||
return connection.localUtils;
|
||||
}
|
||||
|
||||
public JsonArray deviceDescriptors() {
|
||||
return connection.localUtils.deviceDescriptors();
|
||||
return localUtils().deviceDescriptors();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,12 @@ class SerializedValue{
|
||||
String d;
|
||||
String u;
|
||||
String bi;
|
||||
public static class E {
|
||||
String m;
|
||||
String n;
|
||||
String s;
|
||||
}
|
||||
E e;
|
||||
public static class R {
|
||||
String p;
|
||||
String f;
|
||||
|
||||
@@ -53,6 +53,7 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
|
||||
RequestImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
|
||||
if (initializer.has("redirectedFrom")) {
|
||||
redirectedFrom = connection.getExistingObject(initializer.getAsJsonObject("redirectedFrom").get("guid").getAsString());
|
||||
|
||||
@@ -33,6 +33,7 @@ public class RequestOptionsImpl implements RequestOptions {
|
||||
Boolean ignoreHTTPSErrors;
|
||||
Double timeout;
|
||||
Integer maxRedirects;
|
||||
Integer maxRetries;
|
||||
|
||||
@Override
|
||||
public RequestOptions setHeader(String name, String value) {
|
||||
@@ -125,4 +126,10 @@ public class RequestOptionsImpl implements RequestOptions {
|
||||
this.maxRedirects = maxRedirects;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestOptions setMaxRetries(int maxRetries) {
|
||||
this.maxRetries = maxRetries;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
|
||||
ResponseImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
headers = new RawHeaders(asList(gson().fromJson(initializer.getAsJsonArray("headers"), HttpHeader[].class)));
|
||||
request = connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
|
||||
request.timing = gson().fromJson(initializer.get("timing"), Timing.class);
|
||||
|
||||
@@ -38,6 +38,7 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
|
||||
public RouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
request = connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@@ -47,7 +48,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
withLogging("Route.abort", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("errorCode", errorCode);
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
sendMessageAsync("abort", params);
|
||||
});
|
||||
}
|
||||
@@ -135,7 +135,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
params.addProperty("postData", base64);
|
||||
}
|
||||
}
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
params.addProperty("isFallback", isFallback);
|
||||
sendMessageAsync("continue", params);
|
||||
}
|
||||
@@ -231,7 +230,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
if (fetchResponseUid != null) {
|
||||
params.addProperty("fetchResponseUid", fetchResponseUid);
|
||||
}
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
sendMessageAsync("fulfill", params);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.microsoft.playwright.Route;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -99,27 +100,7 @@ class Router {
|
||||
}
|
||||
|
||||
JsonObject interceptionPatterns() {
|
||||
JsonArray jsonPatterns = new JsonArray();
|
||||
for (RouteInfo route : routes) {
|
||||
JsonObject jsonPattern = new JsonObject();
|
||||
Object urlFilter = route.matcher.rawSource;
|
||||
if (urlFilter instanceof String) {
|
||||
jsonPattern.addProperty("glob", (String) urlFilter);
|
||||
} else if (urlFilter instanceof Pattern) {
|
||||
Pattern pattern = (Pattern) urlFilter;
|
||||
jsonPattern.addProperty("regexSource", pattern.pattern());
|
||||
jsonPattern.addProperty("regexFlags", toJsRegexFlags(pattern));
|
||||
} else {
|
||||
// Match all requests.
|
||||
jsonPattern.addProperty("glob", "**/*");
|
||||
jsonPatterns = new JsonArray();
|
||||
jsonPatterns.add(jsonPattern);
|
||||
break;
|
||||
}
|
||||
jsonPatterns.add(jsonPattern);
|
||||
}
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("patterns", jsonPatterns);
|
||||
return result;
|
||||
List<UrlMatcher> matchers = routes.stream().map(r -> r.matcher).collect(Collectors.toList());
|
||||
return Utils.interceptionPatterns(matchers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import com.microsoft.playwright.ElementHandle;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigInteger;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -35,10 +33,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -52,6 +47,7 @@ class Serialization {
|
||||
.registerTypeAdapter(SameSiteAttribute.class, new SameSiteAdapter().nullSafe())
|
||||
.registerTypeAdapter(BrowserChannel.class, new ToLowerCaseAndDashSerializer<BrowserChannel>())
|
||||
.registerTypeAdapter(ColorScheme.class, new ToLowerCaseAndDashSerializer<ColorScheme>())
|
||||
.registerTypeAdapter(Contrast.class, new ToLowerCaseAndDashSerializer<Contrast>())
|
||||
.registerTypeAdapter(Media.class, new ToLowerCaseSerializer<Media>())
|
||||
.registerTypeAdapter(ForcedColors.class, new ToLowerCaseSerializer<ForcedColors>())
|
||||
.registerTypeAdapter(HttpCredentialsSend.class, new ToLowerCaseSerializer<HttpCredentialsSend>())
|
||||
@@ -79,6 +75,7 @@ class Serialization {
|
||||
static final Gson jsonDataSerializer = new GsonBuilder().disableHtmlEscaping()
|
||||
.registerTypeAdapter(Date.class, new DateSerializer())
|
||||
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
|
||||
.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeSerializer())
|
||||
.serializeNulls().create();
|
||||
|
||||
static SerializedError serializeError(Throwable e) {
|
||||
@@ -174,6 +171,14 @@ class Serialization {
|
||||
result.r = new SerializedValue.R();
|
||||
result.r.p = ((Pattern)value).pattern();
|
||||
result.r.f = toJsRegexFlags(((Pattern)value));
|
||||
} else if (value instanceof Exception) {
|
||||
Exception exception = (Exception) value;
|
||||
result.e = new SerializedValue.E();
|
||||
result.e.m = exception.getMessage();
|
||||
result.e.n = exception.getClass().getSimpleName();
|
||||
StringWriter sw = new StringWriter();
|
||||
exception.printStackTrace(new PrintWriter(sw));
|
||||
result.e.s = sw.toString();
|
||||
} else {
|
||||
HashableValue mapKey = new HashableValue(value);
|
||||
Integer id = valueToId.get(mapKey);
|
||||
@@ -251,6 +256,9 @@ class Serialization {
|
||||
return (T)(Date.from(Instant.parse(value.d)));
|
||||
if (value.r != null)
|
||||
return (T)(Pattern.compile(value.r.p, fromJsRegexFlags(value.r.f)));
|
||||
if (value.e != null) {
|
||||
return (T)new Exception(value.e.s);
|
||||
}
|
||||
if (value.v != null) {
|
||||
switch (value.v) {
|
||||
case "undefined":
|
||||
@@ -308,6 +316,9 @@ class Serialization {
|
||||
if (modifiers.contains(KeyboardModifier.CONTROL)) {
|
||||
result.add("Control");
|
||||
}
|
||||
if (modifiers.contains(KeyboardModifier.CONTROLORMETA)) {
|
||||
result.add("ControlOrMeta");
|
||||
}
|
||||
if (modifiers.contains(KeyboardModifier.META)) {
|
||||
result.add("Meta");
|
||||
}
|
||||
@@ -415,6 +426,7 @@ class Serialization {
|
||||
private static boolean isSupported(Type type) {
|
||||
return new TypeToken<Optional<Media>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<ColorScheme>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<Contrast>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<ForcedColors>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<ReducedMotion>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<ViewportSize>>() {}.getType().getTypeName().equals(type.getTypeName());
|
||||
@@ -519,6 +531,13 @@ class Serialization {
|
||||
}
|
||||
}
|
||||
|
||||
private static class OffsetDateTimeSerializer implements JsonSerializer<OffsetDateTime> {
|
||||
@Override
|
||||
public JsonElement serialize(OffsetDateTime src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(dateFormat.format(Date.from(src.toInstant())));
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
|
||||
@Override
|
||||
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
|
||||
@@ -33,6 +33,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
|
||||
TracingImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
}
|
||||
|
||||
private void stopChunkImpl(Path path) {
|
||||
@@ -85,6 +86,25 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
tracingStartChunk(options.name, options.title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void group(String name, GroupOptions options) {
|
||||
withLogging("Tracing.group", () -> groupImpl(name, options));
|
||||
}
|
||||
|
||||
private void groupImpl(String name, GroupOptions options) {
|
||||
if (options == null) {
|
||||
options = new GroupOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("name", name);
|
||||
sendMessage("tracingGroup", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void groupEnd() {
|
||||
withLogging("Tracing.groupEnd", () -> sendMessage("tracingGroupEnd"));
|
||||
}
|
||||
|
||||
private void tracingStartChunk(String name, String title) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (name != null) {
|
||||
|
||||
@@ -18,32 +18,25 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.globToRegex;
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
|
||||
class UrlMatcher {
|
||||
final Object rawSource;
|
||||
private final Predicate<String> predicate;
|
||||
public final String glob;
|
||||
public final Pattern pattern;
|
||||
public final Predicate<String> predicate;
|
||||
|
||||
private static Predicate<String> toPredicate(Pattern pattern) {
|
||||
return s -> pattern.matcher(s).find();
|
||||
}
|
||||
|
||||
static UrlMatcher any() {
|
||||
return new UrlMatcher((Object) null, null);
|
||||
}
|
||||
|
||||
static UrlMatcher forOneOf(URL baseUrl, Object object) {
|
||||
static UrlMatcher forOneOf(URL baseUrl, Object object, LocalUtils localUtils, boolean isWebSocketUrl) {
|
||||
if (object == null) {
|
||||
return UrlMatcher.any();
|
||||
return new UrlMatcher(null, null, null);
|
||||
}
|
||||
if (object instanceof String) {
|
||||
return new UrlMatcher(baseUrl, (String) object);
|
||||
return UrlMatcher.forGlob(baseUrl, (String) object, localUtils, isWebSocketUrl);
|
||||
}
|
||||
if (object instanceof Pattern) {
|
||||
return new UrlMatcher((Pattern) object);
|
||||
@@ -55,34 +48,48 @@ class UrlMatcher {
|
||||
}
|
||||
|
||||
static String resolveUrl(URL baseUrl, String spec) {
|
||||
return resolveUrl(baseUrl.toString(), spec);
|
||||
}
|
||||
|
||||
private static String resolveUrl(String baseUrl, String spec) {
|
||||
if (baseUrl == null) {
|
||||
return spec;
|
||||
}
|
||||
try {
|
||||
return new URL(baseUrl, spec).toString();
|
||||
} catch (MalformedURLException e) {
|
||||
// Join using URI instead of URL since URL doesn't handle ws(s) protocols.
|
||||
return new URI(baseUrl).resolve(spec).toString();
|
||||
} catch (URISyntaxException e) {
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
UrlMatcher(URL base, String url) {
|
||||
this(url, toPredicate(Pattern.compile(globToRegex(resolveUrl(base, url)))).or(s -> url == null || url.equals(s)));
|
||||
static UrlMatcher forGlob(URL baseURL, String glob, LocalUtils localUtils, boolean isWebSocketUrl) {
|
||||
Pattern pattern = localUtils.globToRegex(glob, baseURL != null ? baseURL.toString() : null, isWebSocketUrl);
|
||||
return new UrlMatcher(glob, pattern, null);
|
||||
}
|
||||
|
||||
UrlMatcher(Pattern pattern) {
|
||||
this(pattern, toPredicate(pattern));
|
||||
}
|
||||
UrlMatcher(Predicate<String> predicate) {
|
||||
this(predicate, predicate);
|
||||
this(null, pattern, null);
|
||||
}
|
||||
|
||||
private UrlMatcher(Object rawSource, Predicate<String> predicate) {
|
||||
this.rawSource = rawSource;
|
||||
UrlMatcher(Predicate<String> predicate) {
|
||||
this(null, null, predicate);
|
||||
}
|
||||
|
||||
private UrlMatcher(String glob, Pattern pattern, Predicate<String> predicate) {
|
||||
this.glob = glob;
|
||||
this.pattern = pattern;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
boolean test(String value) {
|
||||
return predicate == null || predicate.test(value);
|
||||
if (pattern != null) {
|
||||
return pattern.matcher(value).find();
|
||||
}
|
||||
if (predicate != null) {
|
||||
return predicate.test(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,25 +97,40 @@ class UrlMatcher {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
UrlMatcher that = (UrlMatcher) o;
|
||||
if (rawSource instanceof Pattern && that.rawSource instanceof Pattern) {
|
||||
Pattern a = (Pattern) rawSource;
|
||||
Pattern b = (Pattern) that.rawSource;
|
||||
return a.pattern().equals(b.pattern()) && a.flags() == b.flags();
|
||||
if (pattern != null) {
|
||||
return that.pattern != null && pattern.pattern().equals(that.pattern.pattern()) && pattern.flags() == that.pattern.flags();
|
||||
}
|
||||
return Objects.equals(rawSource, that.rawSource);
|
||||
if (predicate != null) {
|
||||
return predicate.equals(that.predicate);
|
||||
}
|
||||
if (glob != null) {
|
||||
return glob.equals(that.glob);
|
||||
}
|
||||
return that.pattern == null && that.predicate == null && that.glob == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(rawSource);
|
||||
if (pattern != null) {
|
||||
return pattern.hashCode();
|
||||
}
|
||||
if (predicate != null) {
|
||||
return predicate.hashCode();
|
||||
}
|
||||
if (glob != null) {
|
||||
return glob.hashCode();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (rawSource == null)
|
||||
return "<any>";
|
||||
if (rawSource instanceof Predicate)
|
||||
return "matching predicate";
|
||||
return rawSource.toString();
|
||||
if (glob != null)
|
||||
return String.format("<glob pattern=\"%s\">", glob);
|
||||
if (pattern != null)
|
||||
return String.format("<regex pattern=\"%s\" flags=\"%s\">", pattern.pattern(), toJsRegexFlags(pattern));
|
||||
if (this.predicate != null)
|
||||
return "<predicate>";
|
||||
return "<true>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.ClientCertificate;
|
||||
import com.microsoft.playwright.options.FilePayload;
|
||||
import com.microsoft.playwright.options.HttpHeader;
|
||||
|
||||
@@ -31,12 +31,12 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.toJsonArray;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
|
||||
public class Utils {
|
||||
static <F, T> T convertType(F f, Class<T> t) {
|
||||
@@ -89,79 +89,6 @@ public class Utils {
|
||||
return convertType(f, (Class<T>) f.getClass());
|
||||
}
|
||||
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#escaping
|
||||
static Set<Character> escapeGlobChars = new HashSet<>(Arrays.asList('$', '^', '+', '.', '*', '(', ')', '|', '\\', '?', '{', '}', '[', ']'));
|
||||
|
||||
static String globToRegex(String glob) {
|
||||
StringBuilder tokens = new StringBuilder();
|
||||
tokens.append('^');
|
||||
boolean inGroup = false;
|
||||
for (int i = 0; i < glob.length(); ++i) {
|
||||
char c = glob.charAt(i);
|
||||
if (c == '\\' && i + 1 < glob.length()) {
|
||||
char nextChar = glob.charAt(++i);
|
||||
if (escapeGlobChars.contains(nextChar)) {
|
||||
tokens.append('\\');
|
||||
}
|
||||
tokens.append(nextChar);
|
||||
continue;
|
||||
}
|
||||
if (c == '*') {
|
||||
boolean beforeDeep = i < 1 || glob.charAt(i - 1) == '/';
|
||||
int starCount = 1;
|
||||
while (i + 1 < glob.length() && glob.charAt(i + 1) == '*') {
|
||||
starCount++;
|
||||
i++;
|
||||
}
|
||||
boolean afterDeep = i + 1 >= glob.length() || glob.charAt(i + 1) == '/';
|
||||
boolean isDeep = starCount > 1 && beforeDeep && afterDeep;
|
||||
if (isDeep) {
|
||||
tokens.append("((?:[^/]*(?:\\/|$))*)");
|
||||
i++;
|
||||
} else {
|
||||
tokens.append("([^/]*)");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '?':
|
||||
tokens.append('.');
|
||||
break;
|
||||
case '[':
|
||||
tokens.append('[');
|
||||
break;
|
||||
case ']':
|
||||
tokens.append(']');
|
||||
break;
|
||||
case '{':
|
||||
inGroup = true;
|
||||
tokens.append('(');
|
||||
break;
|
||||
case '}':
|
||||
inGroup = false;
|
||||
tokens.append(')');
|
||||
break;
|
||||
case ',':
|
||||
if (inGroup) {
|
||||
tokens.append('|');
|
||||
break;
|
||||
}
|
||||
tokens.append("\\").append(c);
|
||||
break;
|
||||
default:
|
||||
if (escapeGlobChars.contains(c)) {
|
||||
tokens.append('\\');
|
||||
}
|
||||
tokens.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokens.append('$');
|
||||
return tokens.toString();
|
||||
}
|
||||
|
||||
static String mimeType(Path path) {
|
||||
String mimeType;
|
||||
try {
|
||||
@@ -412,4 +339,70 @@ public class Utils {
|
||||
static String addSourceUrlToScript(String source, Path path) {
|
||||
return source + "\n//# sourceURL=" + path.toString().replace("\n", "");
|
||||
}
|
||||
|
||||
static void addToProtocol(JsonObject params, List<ClientCertificate> clientCertificateList) {
|
||||
if (clientCertificateList == null) {
|
||||
return;
|
||||
}
|
||||
JsonArray clientCertificates = new JsonArray();
|
||||
for (ClientCertificate cert: clientCertificateList) {
|
||||
JsonObject jsonCert = new JsonObject();
|
||||
jsonCert.addProperty("origin", cert.origin);
|
||||
try {
|
||||
String certBase64 = base64Buffer(cert.cert, cert.certPath);
|
||||
if (certBase64 != null) {
|
||||
jsonCert.addProperty("cert", certBase64);
|
||||
}
|
||||
String keyBase64 = base64Buffer(cert.key, cert.keyPath);
|
||||
if (keyBase64 != null) {
|
||||
jsonCert.addProperty("key", keyBase64);
|
||||
}
|
||||
String pfxBase64 = base64Buffer(cert.pfx, cert.pfxPath);
|
||||
if (pfxBase64 != null) {
|
||||
jsonCert.addProperty("pfx", pfxBase64);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read from file", e);
|
||||
}
|
||||
if (cert.passphrase != null) {
|
||||
jsonCert.addProperty("passphrase", cert.passphrase);
|
||||
}
|
||||
clientCertificates.add(jsonCert);
|
||||
}
|
||||
params.remove("clientCertificates");
|
||||
params.add("clientCertificates", clientCertificates);
|
||||
}
|
||||
|
||||
private static String base64Buffer(byte[] bytes, Path path) throws IOException {
|
||||
if (path != null) {
|
||||
bytes = readAllBytes(path);
|
||||
}
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
static JsonObject interceptionPatterns(List<UrlMatcher> matchers) {
|
||||
JsonArray jsonPatterns = new JsonArray();
|
||||
for (UrlMatcher matcher: matchers) {
|
||||
JsonObject jsonPattern = new JsonObject();
|
||||
if (matcher.glob != null) {
|
||||
jsonPattern.addProperty("glob", matcher.glob);
|
||||
} else if (matcher.pattern != null) {
|
||||
jsonPattern.addProperty("regexSource", matcher.pattern.pattern());
|
||||
jsonPattern.addProperty("regexFlags", toJsRegexFlags(matcher.pattern));
|
||||
} else {
|
||||
// Match all requests.
|
||||
jsonPattern.addProperty("glob", "**/*");
|
||||
jsonPatterns = new JsonArray();
|
||||
jsonPatterns.add(jsonPattern);
|
||||
break;
|
||||
}
|
||||
jsonPatterns.add(jsonPattern);
|
||||
}
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("patterns", jsonPatterns);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
|
||||
class WaitableRace<T> implements Waitable<T> {
|
||||
private final Collection<Waitable<T>> waitables;
|
||||
private Waitable<T> firstReady;
|
||||
|
||||
WaitableRace(Collection<Waitable<T>> waitables) {
|
||||
this.waitables = waitables;
|
||||
@@ -27,8 +28,12 @@ class WaitableRace<T> implements Waitable<T> {
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
for (Waitable w : waitables) {
|
||||
if (firstReady != null) {
|
||||
return true;
|
||||
}
|
||||
for (Waitable<T> w : waitables) {
|
||||
if (w.isDone()) {
|
||||
firstReady = w;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -37,14 +42,11 @@ class WaitableRace<T> implements Waitable<T> {
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
assert isDone();
|
||||
dispose();
|
||||
for (Waitable<T> w : waitables) {
|
||||
if (w.isDone()) {
|
||||
return w.get();
|
||||
}
|
||||
try {
|
||||
return firstReady.get();
|
||||
} finally {
|
||||
dispose();
|
||||
}
|
||||
throw new IllegalStateException("At least one element must be ready");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.WebSocketFrame;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
class WebSocketFrameImpl implements WebSocketFrame {
|
||||
private byte[] bytes;
|
||||
private String text;
|
||||
|
||||
WebSocketFrameImpl(String payload, boolean isBase64) {
|
||||
if (isBase64) {
|
||||
bytes = Base64.getDecoder().decode(payload);
|
||||
} else {
|
||||
text = payload;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] binary() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String text() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,7 @@ import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.WebSocket;
|
||||
import com.microsoft.playwright.WebSocketFrame;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
@@ -151,28 +149,6 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
private static class WebSocketFrameImpl implements WebSocketFrame {
|
||||
private final byte[] bytes;
|
||||
|
||||
WebSocketFrameImpl(String payload, boolean isBase64) {
|
||||
if (isBase64) {
|
||||
bytes = Base64.getDecoder().decode(payload);
|
||||
} else {
|
||||
bytes = payload.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] binary() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String text() {
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleEvent(String event, JsonObject parameters) {
|
||||
switch (event) {
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.WebSocketFrame;
|
||||
import com.microsoft.playwright.WebSocketRoute;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class WebSocketRouteImpl extends ChannelOwner implements WebSocketRoute {
|
||||
|
||||
private Consumer<WebSocketFrame> onPageMessage;
|
||||
private BiConsumer<Integer, String> onPageClose;
|
||||
private Consumer<WebSocketFrame> onServerMessage;
|
||||
private BiConsumer<Integer, String> onServerClose;
|
||||
private boolean connected;
|
||||
private WebSocketRoute server = new WebSocketRoute() {
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("wasClean", true);
|
||||
sendMessageAsync("closeServer", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketRoute connectToServer() {
|
||||
throw new PlaywrightException("connectToServer must be called on the page-side WebSocketRoute");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(BiConsumer<Integer, String> handler) {
|
||||
onServerClose = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Consumer<WebSocketFrame> handler) {
|
||||
onServerMessage = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String message) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("message", message);
|
||||
params.addProperty("isBase64", false);
|
||||
sendMessageAsync("sendToServer", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(byte[] message) {
|
||||
JsonObject params = new JsonObject();
|
||||
String base64 = Base64.getEncoder().encodeToString(message);
|
||||
params.addProperty("message", base64);
|
||||
params.addProperty("isBase64", true);
|
||||
sendMessageAsync("sendToServer", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return initializer.get("url").getAsString();
|
||||
}
|
||||
};
|
||||
|
||||
WebSocketRouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("wasClean", true);
|
||||
sendMessageAsync("closePage", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketRoute connectToServer() {
|
||||
if (connected) {
|
||||
throw new PlaywrightException("Already connected to the server");
|
||||
}
|
||||
connected = true;
|
||||
sendMessageAsync("connect");
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(BiConsumer<Integer, String> handler) {
|
||||
onPageClose = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Consumer<WebSocketFrame> handler) {
|
||||
onPageMessage = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String message) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("message", message);
|
||||
params.addProperty("isBase64", false);
|
||||
sendMessageAsync("sendToPage", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(byte[] message) {
|
||||
JsonObject params = new JsonObject();
|
||||
String base64 = Base64.getEncoder().encodeToString(message);
|
||||
params.addProperty("message", base64);
|
||||
params.addProperty("isBase64", true);
|
||||
sendMessageAsync("sendToPage", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return initializer.get("url").getAsString();
|
||||
}
|
||||
|
||||
void afterHandle() {
|
||||
if (this.connected) {
|
||||
return;
|
||||
}
|
||||
// Ensure that websocket is "open" and can send messages without an actual server connection.
|
||||
sendMessageAsync("ensureOpened");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("messageFromPage".equals(event)) {
|
||||
String message = params.get("message").getAsString();
|
||||
boolean isBase64 = params.get("isBase64").getAsBoolean();
|
||||
if (onPageMessage != null) {
|
||||
onPageMessage.accept(new WebSocketFrameImpl(message, isBase64));
|
||||
} else if (connected) {
|
||||
JsonObject messageParams = new JsonObject();
|
||||
messageParams.addProperty("message", message);
|
||||
messageParams.addProperty("isBase64", isBase64);
|
||||
sendMessageAsync("sendToServer", messageParams);
|
||||
}
|
||||
} else if ("messageFromServer".equals(event)) {
|
||||
String message = params.get("message").getAsString();
|
||||
boolean isBase64 = params.get("isBase64").getAsBoolean();
|
||||
if (onServerMessage != null) {
|
||||
onServerMessage.accept(new WebSocketFrameImpl(message, isBase64));
|
||||
} else {
|
||||
JsonObject messageParams = new JsonObject();
|
||||
messageParams.addProperty("message", message);
|
||||
messageParams.addProperty("isBase64", isBase64);
|
||||
sendMessageAsync("sendToPage", messageParams);
|
||||
}
|
||||
} else if ("closePage".equals(event)) {
|
||||
int code = params.get("code").getAsInt();
|
||||
String reason = params.get("reason").getAsString();
|
||||
boolean wasClean = params.get("wasClean").getAsBoolean();
|
||||
if (onPageClose != null) {
|
||||
onPageClose.accept(code, reason);
|
||||
} else {
|
||||
JsonObject closeParams = new JsonObject();
|
||||
closeParams.addProperty("code", code);
|
||||
closeParams.addProperty("reason", reason);
|
||||
closeParams.addProperty("wasClean", wasClean);
|
||||
sendMessageAsync("closeServer", closeParams);
|
||||
}
|
||||
} else if ("closeServer".equals(event)) {
|
||||
int code = params.get("code").getAsInt();
|
||||
String reason = params.get("reason").getAsString();
|
||||
boolean wasClean = params.get("wasClean").getAsBoolean();
|
||||
if (onServerClose != null) {
|
||||
onServerClose.accept(code, reason);
|
||||
} else {
|
||||
JsonObject closeParams = new JsonObject();
|
||||
closeParams.addProperty("code", code);
|
||||
closeParams.addProperty("reason", reason);
|
||||
closeParams.addProperty("wasClean", wasClean);
|
||||
sendMessageAsync("closePage", closeParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.WebSocketRoute;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WebSocketRouter {
|
||||
private List<RouteInfo> routes = new ArrayList<>();
|
||||
|
||||
private static class RouteInfo {
|
||||
final UrlMatcher matcher;
|
||||
private final Consumer<WebSocketRoute> handler;
|
||||
|
||||
RouteInfo(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
this.matcher = matcher;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
void handle(WebSocketRouteImpl route) {
|
||||
handler.accept(route);
|
||||
route.afterHandle();
|
||||
}
|
||||
}
|
||||
|
||||
void add(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
routes.add(0, new RouteInfo(matcher, handler));
|
||||
}
|
||||
|
||||
boolean handle(WebSocketRouteImpl route) {
|
||||
for (RouteInfo routeInfo: routes) {
|
||||
if (routeInfo.matcher.test(route.url())) {
|
||||
routeInfo.handle(route);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JsonObject interceptionPatterns() {
|
||||
List<UrlMatcher> matchers = routes.stream().map(r -> r.matcher).collect(Collectors.toList());
|
||||
return Utils.interceptionPatterns(matchers);
|
||||
}
|
||||
}
|
||||
+97
-15
@@ -16,28 +16,22 @@
|
||||
|
||||
package com.microsoft.playwright.impl.junit;
|
||||
|
||||
import com.microsoft.playwright.Browser;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.impl.Utils;
|
||||
import com.microsoft.playwright.junit.Options;
|
||||
import org.junit.jupiter.api.extension.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static com.microsoft.playwright.impl.junit.ExtensionUtils.*;
|
||||
import static com.microsoft.playwright.impl.junit.PageExtension.cleanUpPage;
|
||||
|
||||
public class BrowserContextExtension implements ParameterResolver, AfterEachCallback {
|
||||
public class BrowserContextExtension implements ParameterResolver, TestWatcher {
|
||||
private static final ThreadLocal<BrowserContext> threadLocalBrowserContext = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext extensionContext) {
|
||||
BrowserContext browserContext = threadLocalBrowserContext.get();
|
||||
threadLocalBrowserContext.remove();
|
||||
if (browserContext != null) {
|
||||
browserContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||
return !isClassHook(extensionContext) && isParameterSupported(parameterContext, extensionContext, BrowserContext.class);
|
||||
@@ -51,6 +45,7 @@ public class BrowserContextExtension implements ParameterResolver, AfterEachCall
|
||||
/**
|
||||
* Returns the BrowserContext that belongs to the current test. Will be created if it doesn't already exist.
|
||||
* <strong>NOTE:</strong> this method is subject to change.
|
||||
*
|
||||
* @param extensionContext the context in which the current test or container is being executed.
|
||||
* @return The BrowserContext that belongs to the current test.
|
||||
*/
|
||||
@@ -66,10 +61,97 @@ public class BrowserContextExtension implements ParameterResolver, AfterEachCall
|
||||
Browser browser = BrowserExtension.getOrCreateBrowser(extensionContext);
|
||||
Browser.NewContextOptions contextOptions = getContextOptions(playwright, options);
|
||||
browserContext = browser.newContext(contextOptions);
|
||||
if (shouldRecordTrace(options)) {
|
||||
Tracing.StartOptions startOptions = new Tracing.StartOptions().setSnapshots(true).setScreenshots(true).setTitle(extensionContext.getDisplayName());
|
||||
if (System.getenv("PLAYWRIGHT_JAVA_SRC") != null) {
|
||||
startOptions.setSources(true);
|
||||
}
|
||||
browserContext.tracing().start(startOptions);
|
||||
}
|
||||
threadLocalBrowserContext.set(browserContext);
|
||||
return browserContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testSuccessful(ExtensionContext extensionContext) {
|
||||
saveTraceWhenOn(extensionContext);
|
||||
closeBrowserContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAborted(ExtensionContext extensionContext, Throwable cause) {
|
||||
saveTraceWhenOn(extensionContext);
|
||||
closeBrowserContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testFailed(ExtensionContext extensionContext, Throwable cause) {
|
||||
Options options = OptionsExtension.getOptions(extensionContext);
|
||||
if (shouldRecordTrace(options)) {
|
||||
saveTrace(extensionContext);
|
||||
}
|
||||
closeBrowserContext();
|
||||
}
|
||||
|
||||
private static void saveTraceWhenOn(ExtensionContext extensionContext) {
|
||||
Options options = OptionsExtension.getOptions(extensionContext);
|
||||
if (options.trace.equals(Options.Trace.ON)) {
|
||||
saveTrace(extensionContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveTrace(ExtensionContext extensionContext) {
|
||||
BrowserContext browserContext = threadLocalBrowserContext.get();
|
||||
if (browserContext == null) {
|
||||
return;
|
||||
}
|
||||
Path outputPath = getOutputPath(extensionContext);
|
||||
createOutputPath(outputPath);
|
||||
Tracing.StopOptions stopOptions = new Tracing.StopOptions().setPath(outputPath.resolve("trace.zip"));
|
||||
browserContext.tracing().stop(stopOptions);
|
||||
}
|
||||
|
||||
private static void createOutputPath(Path outputPath) {
|
||||
if (!Files.exists(outputPath)) {
|
||||
try {
|
||||
Files.createDirectories(outputPath);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getOutputPath(ExtensionContext extensionContext) {
|
||||
BrowserType browserType = BrowserExtension.getBrowser().browserType();
|
||||
Path defaultOutputPath = getDefaultOutputPath(extensionContext);
|
||||
String outputDirName = extensionContext.getRequiredTestClass().getName() + "." +
|
||||
extensionContext.getRequiredTestMethod().getName() + "-" +
|
||||
browserType.name();
|
||||
return defaultOutputPath.resolve(outputDirName);
|
||||
}
|
||||
|
||||
private static Path getDefaultOutputPath(ExtensionContext extensionContext) {
|
||||
Options options = OptionsExtension.getOptions(extensionContext);
|
||||
Path outputPath = options.outputDir;
|
||||
if (outputPath == null) {
|
||||
outputPath = Paths.get(System.getProperty("user.dir")).resolve("test-results");
|
||||
}
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
private void closeBrowserContext() {
|
||||
cleanUpPage();
|
||||
BrowserContext browserContext = threadLocalBrowserContext.get();
|
||||
threadLocalBrowserContext.remove();
|
||||
if (browserContext != null) {
|
||||
browserContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldRecordTrace(Options options) {
|
||||
return options.trace.equals(Options.Trace.ON) || options.trace.equals(Options.Trace.RETAIN_ON_FAILURE);
|
||||
}
|
||||
|
||||
private static Browser.NewContextOptions getContextOptions(Playwright playwright, Options options) {
|
||||
Browser.NewContextOptions contextOptions = Utils.clone(options.contextOptions);
|
||||
if (contextOptions == null) {
|
||||
@@ -94,7 +176,7 @@ public class BrowserContextExtension implements ParameterResolver, AfterEachCall
|
||||
contextOptions.hasTouch = deviceDescriptor.hasTouch;
|
||||
}
|
||||
|
||||
if(options.ignoreHTTPSErrors != null) {
|
||||
if (options.ignoreHTTPSErrors != null) {
|
||||
contextOptions.setIgnoreHTTPSErrors(options.ignoreHTTPSErrors);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,10 @@ public class BrowserExtension implements ParameterResolver, AfterAllCallback {
|
||||
return browser;
|
||||
}
|
||||
|
||||
static Browser getBrowser() {
|
||||
return threadLocalBrowser.get();
|
||||
}
|
||||
|
||||
private static BrowserType.ConnectOptions getConnectOptions(Options options) {
|
||||
BrowserType.ConnectOptions connectOptions = options.connectOptions;
|
||||
if(connectOptions == null) {
|
||||
|
||||
@@ -22,17 +22,8 @@ import org.junit.jupiter.api.extension.*;
|
||||
|
||||
import static com.microsoft.playwright.impl.junit.ExtensionUtils.*;
|
||||
|
||||
public class PageExtension implements ParameterResolver, AfterEachCallback {
|
||||
private static final ThreadLocal<Page> threadLocalPage = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext extensionContext) {
|
||||
Page page = threadLocalPage.get();
|
||||
threadLocalPage.remove();
|
||||
if (page != null) {
|
||||
page.close();
|
||||
}
|
||||
}
|
||||
public class PageExtension implements ParameterResolver {
|
||||
private static final ThreadLocal<Page> threadLocalPage = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
||||
@@ -47,6 +38,7 @@ public class PageExtension implements ParameterResolver, AfterEachCallback {
|
||||
/**
|
||||
* Returns the Page that belongs to the current test. Will be created if it doesn't already exist.
|
||||
* <strong>NOTE:</strong> this method is subject to change.
|
||||
*
|
||||
* @param extensionContext the context in which the current test or container is being executed.
|
||||
* @return The Page that belongs to the current test.
|
||||
*/
|
||||
@@ -61,4 +53,8 @@ public class PageExtension implements ParameterResolver, AfterEachCallback {
|
||||
threadLocalPage.set(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
static void cleanUpPage() {
|
||||
threadLocalPage.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
package com.microsoft.playwright.junit;
|
||||
|
||||
import com.microsoft.playwright.APIRequest;
|
||||
import com.microsoft.playwright.Browser;
|
||||
import com.microsoft.playwright.BrowserType;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* <strong>NOTE:</strong> this API is experimental and is subject to changes.
|
||||
@@ -47,6 +46,26 @@ public class Options {
|
||||
// If this is set, BrowserType.connect will be used. Otherwise, BrowserType.launch will be used.
|
||||
public String wsEndpoint;
|
||||
public BrowserType.ConnectOptions connectOptions;
|
||||
// The dir where test artifacts will be stored
|
||||
public Path outputDir;
|
||||
// When to record traces. Default is OFF.
|
||||
public Trace trace = Trace.OFF;
|
||||
|
||||
public enum Trace {
|
||||
OFF,
|
||||
ON,
|
||||
RETAIN_ON_FAILURE;
|
||||
}
|
||||
|
||||
public Options setTrace(Trace trace) {
|
||||
this.trace = trace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options setOutputDir(Path outputDir) {
|
||||
this.outputDir = outputDir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Options setWsEndpoint(String wsEndpoint) {
|
||||
this.wsEndpoint = wsEndpoint;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ClientCertificate {
|
||||
/**
|
||||
* Exact origin that the certificate is valid for. Origin includes {@code https} protocol, a hostname and optionally a
|
||||
* port.
|
||||
*/
|
||||
public String origin;
|
||||
/**
|
||||
* Path to the file with the certificate in PEM format.
|
||||
*/
|
||||
public Path certPath;
|
||||
/**
|
||||
* Direct value of the certificate in PEM format.
|
||||
*/
|
||||
public byte[] cert;
|
||||
/**
|
||||
* Path to the file with the private key in PEM format.
|
||||
*/
|
||||
public Path keyPath;
|
||||
/**
|
||||
* Direct value of the private key in PEM format.
|
||||
*/
|
||||
public byte[] key;
|
||||
/**
|
||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||
*/
|
||||
public Path pfxPath;
|
||||
/**
|
||||
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||
*/
|
||||
public byte[] pfx;
|
||||
/**
|
||||
* Passphrase for the private key (PEM or PFX).
|
||||
*/
|
||||
public String passphrase;
|
||||
|
||||
public ClientCertificate(String origin) {
|
||||
this.origin = origin;
|
||||
}
|
||||
/**
|
||||
* Path to the file with the certificate in PEM format.
|
||||
*/
|
||||
public ClientCertificate setCertPath(Path certPath) {
|
||||
this.certPath = certPath;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Direct value of the certificate in PEM format.
|
||||
*/
|
||||
public ClientCertificate setCert(byte[] cert) {
|
||||
this.cert = cert;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Path to the file with the private key in PEM format.
|
||||
*/
|
||||
public ClientCertificate setKeyPath(Path keyPath) {
|
||||
this.keyPath = keyPath;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Direct value of the private key in PEM format.
|
||||
*/
|
||||
public ClientCertificate setKey(byte[] key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Path to the PFX or PKCS12 encoded private key and certificate chain.
|
||||
*/
|
||||
public ClientCertificate setPfxPath(Path pfxPath) {
|
||||
this.pfxPath = pfxPath;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Direct value of the PFX or PKCS12 encoded private key and certificate chain.
|
||||
*/
|
||||
public ClientCertificate setPfx(byte[] pfx) {
|
||||
this.pfx = pfx;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Passphrase for the private key (PEM or PFX).
|
||||
*/
|
||||
public ClientCertificate setPassphrase(String passphrase) {
|
||||
this.passphrase = passphrase;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 Contrast {
|
||||
NO_PREFERENCE,
|
||||
MORE
|
||||
}
|
||||
@@ -20,15 +20,16 @@ public class Cookie {
|
||||
public String name;
|
||||
public String value;
|
||||
/**
|
||||
* either url or domain / path are required. Optional.
|
||||
* Either url or domain / path are required. Optional.
|
||||
*/
|
||||
public String url;
|
||||
/**
|
||||
* either url or domain / path are required Optional.
|
||||
* For the cookie to apply to all subdomains as well, prefix domain with a dot, like this: ".example.com". Either url or
|
||||
* domain / path are required. Optional.
|
||||
*/
|
||||
public String domain;
|
||||
/**
|
||||
* either url or domain / path are required Optional.
|
||||
* Either url or domain / path are required Optional.
|
||||
*/
|
||||
public String path;
|
||||
/**
|
||||
@@ -53,21 +54,22 @@ public class Cookie {
|
||||
this.value = value;
|
||||
}
|
||||
/**
|
||||
* either url or domain / path are required. Optional.
|
||||
* Either url or domain / path are required. Optional.
|
||||
*/
|
||||
public Cookie setUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* either url or domain / path are required Optional.
|
||||
* For the cookie to apply to all subdomains as well, prefix domain with a dot, like this: ".example.com". Either url or
|
||||
* domain / path are required. Optional.
|
||||
*/
|
||||
public Cookie setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* either url or domain / path are required Optional.
|
||||
* Either url or domain / path are required Optional.
|
||||
*/
|
||||
public Cookie setPath(String path) {
|
||||
this.path = path;
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.nio.file.Path;
|
||||
* The {@code FormData} is used create form data that is sent via {@code APIRequestContext}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* .set("firstName", "John")
|
||||
* .set("lastName", "Doe")
|
||||
@@ -43,7 +43,7 @@ public interface FormData {
|
||||
* existing set of values.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .append("firstName", "John")
|
||||
@@ -70,7 +70,7 @@ public interface FormData {
|
||||
* existing set of values.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .append("firstName", "John")
|
||||
@@ -97,7 +97,7 @@ public interface FormData {
|
||||
* existing set of values.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .append("firstName", "John")
|
||||
@@ -124,7 +124,7 @@ public interface FormData {
|
||||
* existing set of values.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .append("firstName", "John")
|
||||
@@ -151,7 +151,7 @@ public interface FormData {
|
||||
* existing set of values.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .append("firstName", "John")
|
||||
@@ -179,7 +179,7 @@ public interface FormData {
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
@@ -200,7 +200,7 @@ public interface FormData {
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
@@ -221,7 +221,7 @@ public interface FormData {
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
@@ -242,7 +242,7 @@ public interface FormData {
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
@@ -263,7 +263,7 @@ public interface FormData {
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* // ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 Location {
|
||||
public String file;
|
||||
public Integer line;
|
||||
public Integer column;
|
||||
|
||||
public Location(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
public Location setLine(int line) {
|
||||
this.line = line;
|
||||
return this;
|
||||
}
|
||||
public Location setColumn(int column) {
|
||||
this.column = column;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -133,6 +133,15 @@ public interface RequestOptions {
|
||||
* @since v1.26
|
||||
*/
|
||||
RequestOptions setMaxRedirects(int maxRedirects);
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param maxRetries Maximum number of times network errors should be retried. Currently only {@code ECONNRESET} error is retried. Does not
|
||||
* retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to {@code 0} - no
|
||||
* retries.
|
||||
* @since v1.46
|
||||
*/
|
||||
RequestOptions setMaxRetries(int maxRetries);
|
||||
/**
|
||||
* Changes the request method (e.g. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">PUT</a> or <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a>).
|
||||
|
||||
@@ -19,11 +19,15 @@ package com.microsoft.playwright;
|
||||
import com.sun.net.httpserver.HttpsConfigurator;
|
||||
import com.sun.net.httpserver.HttpsParameters;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.*;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
class HttpsConfiguratorImpl extends HttpsConfigurator {
|
||||
|
||||
@@ -31,7 +35,7 @@ class HttpsConfiguratorImpl extends HttpsConfigurator {
|
||||
return new HttpsConfiguratorImpl(createSSLContext());
|
||||
}
|
||||
|
||||
private HttpsConfiguratorImpl(SSLContext context) {
|
||||
HttpsConfiguratorImpl(SSLContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@@ -39,8 +43,8 @@ class HttpsConfiguratorImpl extends HttpsConfigurator {
|
||||
public void configure(HttpsParameters params) {
|
||||
SSLContext sslContext = getSSLContext();
|
||||
SSLParameters sslParams = sslContext.getDefaultSSLParameters();
|
||||
sslParams.setNeedClientAuth(true);
|
||||
params.setNeedClientAuth(true);
|
||||
sslParams.setWantClientAuth(true);
|
||||
params.setWantClientAuth(true);
|
||||
params.setSSLParameters(sslParams);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.sun.net.httpserver.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -73,11 +72,8 @@ public class Server implements HttpHandler {
|
||||
} else {
|
||||
server = HttpServer.create(new InetSocketAddress("localhost", port), 0);
|
||||
}
|
||||
|
||||
server.createContext("/", this);
|
||||
server.setExecutor(null); // creates a default executor
|
||||
|
||||
File cwd = FileSystems.getDefault().getPath(".").toFile();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@@ -222,7 +218,7 @@ public class Server implements HttpHandler {
|
||||
}
|
||||
long contentLength = body.size();
|
||||
// -1 means no body, 0 means chunked encoding.
|
||||
exchange.sendResponseHeaders(200, contentLength == 0 ? -1 : contentLength);
|
||||
exchange.sendResponseHeaders(200, (contentLength == 0 || exchange.getRequestMethod().equals("HEAD")) ? -1 : contentLength);
|
||||
if (contentLength > 0) {
|
||||
exchange.getResponseBody().write(body.toByteArray());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.cert.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ServerWithClientCertificate implements HttpHandler {
|
||||
private final HttpServer server;
|
||||
final String origin;
|
||||
final String crossOrigin;
|
||||
final String url;
|
||||
KeyStore keyStore;
|
||||
|
||||
static ServerWithClientCertificate create(int port) throws IOException {
|
||||
return new ServerWithClientCertificate(port);
|
||||
}
|
||||
|
||||
private ServerWithClientCertificate(int port) throws IOException {
|
||||
origin = "https://localhost:" + port;
|
||||
crossOrigin = "https://127.0.0.1:" + port;;
|
||||
url = origin + "/index.html";
|
||||
HttpsServer httpsServer = HttpsServer.create(new InetSocketAddress("localhost", port), 0);
|
||||
httpsServer.setHttpsConfigurator(new HttpsConfiguratorImpl(loadCertificates()));
|
||||
server = httpsServer;
|
||||
server.createContext("/", this);
|
||||
server.setExecutor(null); // creates a default executor
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
server.stop(0);
|
||||
}
|
||||
|
||||
private SSLContext loadCertificates() {
|
||||
try {
|
||||
// Create an SSL context
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
|
||||
// Load the keystore from file
|
||||
char[] password = "".toCharArray(); // the password you set during the PKCS12 export
|
||||
keyStore = KeyStore.getInstance("PKCS12");
|
||||
InputStream fis = HttpsConfiguratorImpl.class.getClassLoader().getResourceAsStream(
|
||||
"resources/client-certificates/server/server_keystore.p12");
|
||||
keyStore.load(fis, password);
|
||||
|
||||
// Set up the KeyManagerFactory to use the keystore
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(keyStore, password);
|
||||
|
||||
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
List<X509Certificate> certs = new ArrayList<>();
|
||||
try {
|
||||
for (String alias : Collections.list(keyStore.aliases())) {
|
||||
certs.add((X509Certificate) keyStore.getCertificate(alias));
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return certs.toArray(new X509Certificate[0]);
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] clientCerts, String authType) throws CertificateException {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize the SSL context
|
||||
sslContext.init(kmf.getKeyManagers(), trustAllCerts, null);
|
||||
return sslContext;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateCertChain(Certificate[] clientCerts) {
|
||||
try {
|
||||
// Create CertPath from the provided client certificates
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
CertPath certPath = factory.generateCertPath(Arrays.asList(clientCerts));
|
||||
|
||||
// Extract Trust Anchors from the trust store
|
||||
Set<TrustAnchor> trustAnchors = new HashSet<>();
|
||||
for (String alias : Collections.list(keyStore.aliases())) {
|
||||
X509Certificate trustedCert = (X509Certificate) keyStore.getCertificate(alias);
|
||||
if (trustedCert != null) {
|
||||
trustAnchors.add(new TrustAnchor(trustedCert, null));
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize PKIX parameters
|
||||
PKIXParameters params = new PKIXParameters(trustAnchors);
|
||||
params.setRevocationEnabled(false); // Set to true if you want to enable CRL checking
|
||||
|
||||
// Validate the certification path
|
||||
CertPathValidator certPathValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType());
|
||||
certPathValidator.validate(certPath, params);
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String div(String testId, String message) {
|
||||
return "<div data-testid='" + testId + "'>" + message + "</div>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
SSLSession sslSession = ((HttpsExchange) exchange).getSSLSession();
|
||||
String response = div("servername", sslSession.getPeerHost());
|
||||
try {
|
||||
Certificate[] certs = sslSession.getPeerCertificates();
|
||||
X509Certificate cert = (X509Certificate) certs[0];
|
||||
exchange.getResponseHeaders().add("Content-Type", "text/html");
|
||||
if (validateCertChain(certs)) {
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
response += div("message", String.format("Hello %s, your certificate was issued by %s!",
|
||||
cert.getSubjectX500Principal().getName(), cert.getIssuerX500Principal().getName()));
|
||||
} else {
|
||||
response += div("message", String.format("Sorry %s, certificates from %s are not welcome here.",
|
||||
cert.getSubjectX500Principal().getName(), cert.getIssuerX500Principal().getName()));
|
||||
exchange.sendResponseHeaders(403, 0);
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
response += div("message", "Sorry, but you need to provide a client certificate to continue.");
|
||||
exchange.sendResponseHeaders(401, 0);
|
||||
}
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import com.microsoft.playwright.options.SameSiteAttribute;
|
||||
|
||||
import javax.sql.rowset.Predicate;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.Provider;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -299,6 +299,13 @@ public class TestBrowserContextBasic {
|
||||
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void waitForConditionThatMayChangeToFalse(BrowserContext context) {
|
||||
int[] var = {0};
|
||||
context.waitForCondition(() -> ++var[0] == 1);
|
||||
assertEquals(1, var[0], "The predicate should be called only once.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPropagateCloseReasonToPendingActions(Browser browser) {
|
||||
BrowserContext context = browser.newContext();
|
||||
|
||||
+25
-7
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -49,7 +50,12 @@ public class TestBrowserContextCDPSession extends TestBase {
|
||||
cdpSession.send("Network.enable");
|
||||
|
||||
List<JsonElement> events = new ArrayList<>();
|
||||
cdpSession.on("Network.requestWillBeSent", events::add);
|
||||
cdpSession.on("Network.requestWillBeSent", (JsonObject jsonObject) -> {
|
||||
// Only register main request, ignore favicon requests.
|
||||
if ("Document".equals(jsonObject.get("type").getAsString())) {
|
||||
events.add(jsonObject);
|
||||
}
|
||||
});
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
|
||||
assertEquals(1, events.size());
|
||||
@@ -126,7 +132,7 @@ public class TestBrowserContextCDPSession extends TestBase {
|
||||
page.close();
|
||||
|
||||
PlaywrightException exception = assertThrows(PlaywrightException.class, session::detach);
|
||||
assertTrue(exception.getMessage().contains("Target page, context or browser has been closed"));
|
||||
assertTrue(exception.getMessage().contains("Target page, context or browser has been closed"), exception.getMessage());
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -136,8 +142,14 @@ public class TestBrowserContextCDPSession extends TestBase {
|
||||
cdpSession.send("Network.enable");
|
||||
|
||||
List<JsonObject> events = new ArrayList<>();
|
||||
cdpSession.on("Network.requestWillBeSent", events::add);
|
||||
cdpSession.on("Network.requestWillBeSent", events::add);
|
||||
Consumer<JsonObject> listener1 = (JsonObject jsonObject) -> {
|
||||
// Only register main request, ignore favicon requests.
|
||||
if ("Document".equals(jsonObject.get("type").getAsString())) {
|
||||
events.add(jsonObject);
|
||||
}
|
||||
};
|
||||
cdpSession.on("Network.requestWillBeSent", listener1);
|
||||
cdpSession.on("Network.requestWillBeSent", listener1);
|
||||
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals(2, events.size());
|
||||
@@ -149,9 +161,15 @@ public class TestBrowserContextCDPSession extends TestBase {
|
||||
cdpSession.send("Network.enable");
|
||||
|
||||
List<JsonObject> events = new ArrayList<>();
|
||||
Consumer<JsonObject> listener1 = events::add;
|
||||
Consumer<JsonObject> listener1 = (JsonObject jsonObject) -> {
|
||||
// Only register main request, ignore favicon requests.
|
||||
if ("Document".equals(jsonObject.get("type").getAsString())) {
|
||||
events.add(jsonObject);
|
||||
}
|
||||
};
|
||||
Consumer<JsonObject> listener2 = listener1::accept;
|
||||
cdpSession.on("Network.requestWillBeSent", listener1);
|
||||
cdpSession.on("Network.requestWillBeSent", events::add);
|
||||
cdpSession.on("Network.requestWillBeSent", listener2);
|
||||
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals(2, events.size());
|
||||
@@ -160,6 +178,6 @@ public class TestBrowserContextCDPSession extends TestBase {
|
||||
events.clear();
|
||||
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals(1, events.size());
|
||||
assertEquals(1, events.size(), new Gson().toJson(events));
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -25,12 +25,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestBrowserContextCredentials extends TestBase {
|
||||
|
||||
static boolean isChromiumHeadful() {
|
||||
return isChromium() && isHeadful();
|
||||
static boolean isChromiumHeadedLike() {
|
||||
// --headless=new, the default in all Chromium channels, is like headless.
|
||||
return isChromium() && (isHeadful() || getBrowserChannelFromEnv() != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="isChromiumHeadful", disabledReason="fail")
|
||||
@DisabledIf(value="isChromiumHeadedLike", disabledReason="fail")
|
||||
void shouldFailWithoutCredentials() {
|
||||
server.setAuth("/empty.html", "user", "pass");
|
||||
Response response = page.navigate(server.EMPTY_PAGE);
|
||||
@@ -103,6 +104,7 @@ public class TestBrowserContextCredentials extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="isChromiumHeadedLike", disabledReason="fail")
|
||||
void shouldFailWithCorrectCredentialsAndWrongOriginScheme() {
|
||||
server.setAuth("/empty.html", "user", "pass");
|
||||
final HttpCredentials httpCredentials = new HttpCredentials("user", "pass");
|
||||
@@ -115,6 +117,7 @@ public class TestBrowserContextCredentials extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="isChromiumHeadedLike", disabledReason="fail")
|
||||
void shouldFailWithCorrectCredentialsAndWrongOriginHostname() {
|
||||
server.setAuth("/empty.html", "user", "pass");
|
||||
final HttpCredentials httpCredentials = new HttpCredentials("user", "pass");
|
||||
@@ -127,6 +130,7 @@ public class TestBrowserContextCredentials extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="isChromiumHeadedLike", disabledReason="fail")
|
||||
void shouldFailWithCorrectCredentialsAndWrongOriginPort() {
|
||||
server.setAuth("/empty.html", "user", "pass");
|
||||
final HttpCredentials httpCredentials = new HttpCredentials("user", "pass");
|
||||
|
||||
@@ -22,18 +22,20 @@ import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static com.microsoft.playwright.Utils.*;
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -131,7 +133,7 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
context.request().get(server.EMPTY_PAGE + "?p1=foo",
|
||||
RequestOptions.create().setQueryParam("p1", "v1").setQueryParam("парам2", "знач2"));
|
||||
assertNotNull(req.get());
|
||||
assertEquals("/empty.html?p1=v1&%D0%BF%D0%B0%D1%80%D0%B0%D0%BC2=%D0%B7%D0%BD%D0%B0%D1%872", req.get().url);
|
||||
assertEquals("/empty.html?p1=foo&p1=v1&%D0%BF%D0%B0%D1%80%D0%B0%D0%BC2=%D0%B7%D0%BD%D0%B0%D1%872", req.get().url);
|
||||
}
|
||||
|
||||
;
|
||||
@@ -217,7 +219,7 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
writer.write("<title>Served by the proxy</title>");
|
||||
}
|
||||
});
|
||||
try (Browser browser = browserType.launch(new BrowserType.LaunchOptions().setProxy("http://per-context"))) {
|
||||
try (Browser browser = browserType.launch()) {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setProxy("localhost:" + server.PORT));
|
||||
Future<Server.Request> request = server.futureRequest("/target.html");
|
||||
APIResponse response = context.request().get("http://non-existent.com/target.html");
|
||||
@@ -521,6 +523,16 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
new String(req.get().postBody));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportOffsetDateTimeInData() throws ExecutionException, InterruptedException {
|
||||
APIRequestContext request = playwright.request().newContext();
|
||||
OffsetDateTime offsetDateTime = OffsetDateTime.parse("2024-07-10T10:15:30-08:00");
|
||||
Future<Server.Request> serverRequest = server.futureRequest("/empty.html");
|
||||
request.get(server.EMPTY_PAGE, RequestOptions.create().setData(mapOf("date", offsetDateTime)));
|
||||
byte[] body = serverRequest.get().postBody;
|
||||
assertEquals("{\"date\":\"2024-07-10T18:15:30.000Z\"}", new String(body));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportApplicationXWwwFormUrlencoded() throws ExecutionException, InterruptedException {
|
||||
Future<Server.Request> req = server.futureRequest("/empty.html");
|
||||
@@ -854,4 +866,28 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.EMPTY_PAGE));
|
||||
assertTrue(e.getMessage().contains("Test ended."), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRetryECONNRESET() {
|
||||
int[] requestCount = {0};
|
||||
server.setRoute("/test", exchange -> {
|
||||
if (requestCount[0]++ < 3) {
|
||||
exchange.close();
|
||||
return;
|
||||
}
|
||||
exchange.getResponseHeaders().add("Content-Type", "text/plain");
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("Hello!");
|
||||
}
|
||||
});
|
||||
|
||||
APIRequestContext requestContext = context.request();
|
||||
APIResponse response = requestContext.get(server.PREFIX + "/test",
|
||||
RequestOptions.create().setMaxRetries(3));
|
||||
|
||||
assertEquals(200, response.status());
|
||||
assertEquals("Hello!", response.text());
|
||||
assertEquals(4, requestCount[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,31 +29,6 @@ import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestBrowserContextProxy extends TestBase {
|
||||
|
||||
@Override
|
||||
@BeforeAll
|
||||
// Hide base class method to provide extra option.
|
||||
void launchBrowser() {
|
||||
BrowserType.LaunchOptions options = createLaunchOptions();
|
||||
options.setProxy(new Proxy("per-context"));
|
||||
launchBrowser(options);
|
||||
}
|
||||
|
||||
static boolean isChromiumWindows() {
|
||||
return isChromium() && isWindows;
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf(value="isChromiumWindows", disabledReason="Platform-specific")
|
||||
void shouldThrowForMissingGlobalProxyOnChromiumWindows() {
|
||||
try (Browser browser = browserType.launch(createLaunchOptions())) {
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
|
||||
browser.newContext(new Browser.NewContextOptions().setProxy("localhost:" + server.PORT));
|
||||
});
|
||||
assertTrue(e.getMessage().contains("Browser needs to be launched with the global proxy"));
|
||||
}
|
||||
}
|
||||
|
||||
void shouldThrowForBadServerValue() {
|
||||
// Enforced by compiler in Java
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.nio.file.Path;
|
||||
|
||||
import static com.microsoft.playwright.Utils.assertJsonEquals;
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestBrowserContextStorageState extends TestBase {
|
||||
@@ -169,4 +170,101 @@ public class TestBrowserContextStorageState extends TestBase {
|
||||
" }]\n" +
|
||||
"}]}", new Gson().fromJson(storageState, JsonObject.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportIndexedDB() {
|
||||
page.navigate(server.PREFIX + "/to-do-notifications/index.html");
|
||||
page.locator("label:has-text('Task title')").fill("Pet the cat");
|
||||
page.locator("label:has-text('Hours')").fill("1");
|
||||
page.locator("label:has-text('Mins')").fill("1");
|
||||
page.locator("text=Add Task").click();
|
||||
|
||||
String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
|
||||
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
|
||||
" {\n" +
|
||||
" \"origin\": \"" + server.PREFIX + "\",\n" +
|
||||
" \"localStorage\": [],\n" +
|
||||
" \"indexedDB\": [\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"toDoList\",\n" +
|
||||
" \"version\": 4,\n" +
|
||||
" \"stores\": [\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"toDoList\",\n" +
|
||||
" \"autoIncrement\": false,\n" +
|
||||
" \"keyPath\": \"taskTitle\",\n" +
|
||||
" \"records\": [\n" +
|
||||
" {\n" +
|
||||
" \"valueEncoded\": {\n" +
|
||||
" \"id\": 1,\n" +
|
||||
" \"o\": [\n" +
|
||||
" {\"k\": \"taskTitle\", \"v\": \"Pet the cat\"},\n" +
|
||||
" {\"k\": \"hours\", \"v\": \"1\"},\n" +
|
||||
" {\"k\": \"minutes\", \"v\": \"1\"},\n" +
|
||||
" {\"k\": \"day\", \"v\": \"01\"},\n" +
|
||||
" {\"k\": \"month\", \"v\": \"January\"},\n" +
|
||||
" {\"k\": \"year\", \"v\": \"2025\"},\n" +
|
||||
" {\"k\": \"notified\", \"v\": \"no\"},\n" +
|
||||
" {\"k\": \"signature\", \"v\": { \"ta\": {\"b\":\"c2lnbmVkIGJ5IHNpbW9u\",\"k\":\"ui8\"}}}\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"indexes\": [\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"day\",\n" +
|
||||
" \"keyPath\": \"day\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"hours\",\n" +
|
||||
" \"keyPath\": \"hours\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"minutes\",\n" +
|
||||
" \"keyPath\": \"minutes\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"month\",\n" +
|
||||
" \"keyPath\": \"month\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"notified\",\n" +
|
||||
" \"keyPath\": \"notified\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"year\",\n" +
|
||||
" \"keyPath\": \"year\",\n" +
|
||||
" \"multiEntry\": false,\n" +
|
||||
" \"unique\": false\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
"]}", new Gson().fromJson(storageState, JsonObject.class));
|
||||
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setStorageState(storageState));
|
||||
assertEquals(storageState, context.storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true)));
|
||||
|
||||
Page recreatedPage = context.newPage();
|
||||
recreatedPage.navigate(server.PREFIX + "/to-do-notifications/index.html");
|
||||
assertThat(recreatedPage.locator("#task-list")).matchesAriaSnapshot("\n" +
|
||||
" - list:\n" +
|
||||
" - listitem:\n" +
|
||||
" - text: /Pet the cat/\n");
|
||||
assertEquals("{\"cookies\":[],\"origins\":[]}", context.storageState(
|
||||
new BrowserContext.StorageStateOptions().setIndexedDB(false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.ClientCertificate;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static com.microsoft.playwright.Utils.nextFreePort;
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestClientCertificates extends TestBase {
|
||||
private ServerWithClientCertificate customServer;
|
||||
|
||||
private static Path asset(String path) {
|
||||
return Paths.get("src/test/resources/" + path).toAbsolutePath();
|
||||
}
|
||||
|
||||
private static String origin(String urlString) {
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
String origin = url.getProtocol() + "://" + url.getHost();
|
||||
if (url.getPort() != -1 && url.getPort() != url.getDefaultPort()) {
|
||||
origin += ":" + url.getPort();
|
||||
}
|
||||
return origin;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
@Override
|
||||
void startServer() throws IOException {
|
||||
super.startServer();
|
||||
customServer = ServerWithClientCertificate.create(nextFreePort());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@Override
|
||||
void stopServer() {
|
||||
if (customServer != null) {
|
||||
customServer.stop();
|
||||
customServer = null;
|
||||
}
|
||||
super.stopServer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailWithNoClientCertificatesProvided() {
|
||||
APIRequestContext request = playwright.request().newContext(
|
||||
new APIRequest.NewContextOptions().setIgnoreHTTPSErrors(true));
|
||||
APIResponse response = request.get(customServer.url);
|
||||
assertTrue(response.text().contains("Sorry, but you need to provide a client certificate to continue."), response.text());
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldKeepSupportingHttp() {
|
||||
APIRequest.NewContextOptions requestOptions = new APIRequest.NewContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(origin(server.PREFIX))
|
||||
.setCertPath(asset("client-certificates/client/trusted/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/trusted/key.pem"))));
|
||||
APIRequestContext request = playwright.request().newContext(requestOptions);
|
||||
APIResponse response = request.get(server.PREFIX + "/one-style.html");
|
||||
assertEquals(server.PREFIX + "/one-style.html", response.url());
|
||||
assertEquals(200, response.status());
|
||||
assertTrue(response.text().contains("<div>hello, world!</div>"));
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowWithUntrustedClientCerts() {
|
||||
APIRequest.NewContextOptions requestOptions = new APIRequest.NewContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCertPath(asset("client-certificates/client/self-signed/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/self-signed/key.pem"))));
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(requestOptions);
|
||||
APIResponse response = request.get(customServer.url);
|
||||
|
||||
assertEquals(customServer.url, response.url());
|
||||
assertEquals(403, response.status());
|
||||
assertTrue(response.text().contains("Sorry CN=Bob, certificates from CN=Bob are not welcome here."), response.text());
|
||||
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passWithTrustedClientCertificates() {
|
||||
APIRequest.NewContextOptions requestOptions = new APIRequest.NewContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCertPath(asset("client-certificates/client/trusted/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/trusted/key.pem"))));
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(requestOptions);
|
||||
APIResponse response = request.get(customServer.url);
|
||||
|
||||
assertEquals(customServer.url, response.url());
|
||||
assertEquals(200, response.status());
|
||||
assertTrue(response.text().contains("Hello CN=Alice, your certificate was issued by O=Client Certificate Demo,CN=localhost!"), response.text());
|
||||
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passWithTrustedClientCertificatesPfx() {
|
||||
APIRequest.NewContextOptions requestOptions = new APIRequest.NewContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setPfxPath(asset("client-certificates/client/trusted/client_keystore.p12"))
|
||||
.setPassphrase("passphrase")));
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(requestOptions);
|
||||
APIResponse response = request.get(customServer.url);
|
||||
|
||||
assertEquals(customServer.url, response.url());
|
||||
assertEquals(200, response.status());
|
||||
assertTrue(response.text().contains("Hello CN=Alice, your certificate was issued by O=Client Certificate Demo,CN=localhost!"), response.text());
|
||||
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
static boolean isWebKitMacOS() {
|
||||
return isWebKit() && isMac;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestClientCertificates#isWebKitMacOS", disabledReason="The network connection was lost.")
|
||||
public void shouldWorkWithBrowserNewContext() {
|
||||
Browser.NewContextOptions options = new Browser.NewContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCertPath(asset("client-certificates/client/trusted/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/trusted/key.pem"))));
|
||||
|
||||
try (BrowserContext context = browser.newContext(options)) {
|
||||
Page page = context.newPage();
|
||||
{
|
||||
APIResponse response = page.request().get(customServer.crossOrigin);
|
||||
assertTrue(response.text().contains("Sorry, but you need to provide a client certificate to continue."), response.text());
|
||||
}
|
||||
{
|
||||
page.navigate(customServer.crossOrigin);
|
||||
assertThat(page.getByTestId("message")).hasText("Sorry, but you need to provide a client certificate to continue.");
|
||||
}
|
||||
page.navigate(customServer.url);
|
||||
assertThat(page.getByText("Hello CN=Alice")).isVisible();
|
||||
APIResponse response = page.request().get(customServer.url);
|
||||
assertTrue(response.text().contains("Hello CN=Alice"), response.text());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestClientCertificates#isWebKitMacOS", disabledReason="The network connection was lost.")
|
||||
public void shouldWorkWithBrowserNewPage() {
|
||||
Browser.NewPageOptions options = new Browser.NewPageOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCertPath(asset("client-certificates/client/trusted/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/trusted/key.pem"))));
|
||||
|
||||
try (Page page = browser.newPage(options)) {
|
||||
{
|
||||
page.navigate(customServer.crossOrigin);
|
||||
assertThat(page.getByTestId("message")).hasText("Sorry, but you need to provide a client certificate to continue.");
|
||||
}
|
||||
{
|
||||
APIResponse response = page.request().get(customServer.crossOrigin);
|
||||
assertTrue(response.text().contains("Sorry, but you need to provide a client certificate to continue."), response.text());
|
||||
}
|
||||
page.navigate(customServer.url);
|
||||
assertThat(page.getByText("Hello CN=Alice")).isVisible();
|
||||
APIResponse response = page.request().get(customServer.url);
|
||||
assertTrue(response.text().contains("Hello CN=Alice"), response.text());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestClientCertificates#isWebKitMacOS", disabledReason="The network connection was lost.")
|
||||
public void shouldWorkWithBrowserNewPageWhenPassingAsContent() throws IOException {
|
||||
Browser.NewPageOptions options = new Browser.NewPageOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCert(readAllBytes(asset("client-certificates/client/trusted/cert.pem")))
|
||||
.setKey(readAllBytes(asset("client-certificates/client/trusted/key.pem")))));
|
||||
|
||||
try (Page page = browser.newPage(options)) {
|
||||
{
|
||||
page.navigate(customServer.crossOrigin);
|
||||
assertThat(page.getByTestId("message")).hasText("Sorry, but you need to provide a client certificate to continue.");
|
||||
}
|
||||
{
|
||||
APIResponse response = page.request().get(customServer.crossOrigin);
|
||||
assertTrue(response.text().contains("Sorry, but you need to provide a client certificate to continue."), response.text());
|
||||
}
|
||||
page.navigate(customServer.url);
|
||||
assertThat(page.getByText("Hello CN=Alice")).isVisible();
|
||||
APIResponse response = page.request().get(customServer.url);
|
||||
assertTrue(response.text().contains("Hello CN=Alice"), response.text());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestClientCertificates#isWebKitMacOS", disabledReason="The network connection was lost.")
|
||||
public void shouldWorkWithBrowserLaunchPersistentContext(@TempDir Path tmpDir) {
|
||||
BrowserType.LaunchPersistentContextOptions options = new BrowserType.LaunchPersistentContextOptions()
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setCertPath(asset("client-certificates/client/trusted/cert.pem"))
|
||||
.setKeyPath(asset("client-certificates/client/trusted/key.pem"))));
|
||||
|
||||
try (BrowserContext context = browser.browserType().launchPersistentContext(tmpDir.resolve("profile") , options)) {
|
||||
Page page = context.pages().get(0);
|
||||
{
|
||||
page.navigate(customServer.crossOrigin);
|
||||
assertThat(page.getByTestId("message")).hasText("Sorry, but you need to provide a client certificate to continue.");
|
||||
}
|
||||
{
|
||||
APIResponse response = page.request().get(customServer.crossOrigin);
|
||||
assertTrue(response.text().contains("Sorry, but you need to provide a client certificate to continue."), response.text());
|
||||
}
|
||||
page.navigate(customServer.url);
|
||||
assertThat(page.getByText("Hello CN=Alice")).isVisible();
|
||||
APIResponse response = page.request().get(customServer.url);
|
||||
assertTrue(response.text().contains("Hello CN=Alice"), response.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.Contrast;
|
||||
import com.microsoft.playwright.options.Geolocation;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
@@ -28,6 +29,7 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -168,35 +170,6 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
browserContext3.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRestoreCookiesFromUserDataDir() throws IOException {
|
||||
// TODO: test.flaky(browserName === "chromium");
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
BrowserType.LaunchPersistentContextOptions browserOptions = null;
|
||||
BrowserContext browserContext = browserType.launchPersistentContext(userDataDir, browserOptions);
|
||||
Page page = browserContext.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Object documentCookie = page.evaluate("() => {\n" +
|
||||
" document.cookie = 'doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT';\n" +
|
||||
" return document.cookie;\n" +
|
||||
" }");
|
||||
assertEquals("doSomethingOnlyOnce=true", documentCookie);
|
||||
browserContext.close();
|
||||
|
||||
BrowserContext browserContext2 = browserType.launchPersistentContext(userDataDir, browserOptions);
|
||||
Page page2 = browserContext2.newPage();
|
||||
page2.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("doSomethingOnlyOnce=true", page2.evaluate("() => document.cookie"));
|
||||
browserContext2.close();
|
||||
|
||||
Path userDataDir2 = tempDir.resolve("user-data-dir-2");
|
||||
BrowserContext browserContext3 = browserType.launchPersistentContext(userDataDir2, browserOptions);
|
||||
Page page3 = browserContext3.newPage();
|
||||
page3.navigate(server.EMPTY_PAGE);
|
||||
assertNotEquals("doSomethingOnlyOnce=true", page3.evaluate("() => document.cookie"));
|
||||
browserContext3.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveDefaultURLWhenLaunchingBrowser() {
|
||||
launchPersistent();
|
||||
@@ -311,4 +284,27 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
assertEquals(1, fields.size());
|
||||
assertEquals("200MB.zip", fields.get(0).filename);
|
||||
assertEquals(200 * 1024 * 1024, fields.get(0).content.length());
|
||||
}}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportContrastOption() {
|
||||
Page page = launchPersistent(new BrowserType.LaunchPersistentContextOptions().setContrast(Contrast.MORE));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-contrast: more)').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-contrast: no-preference)').matches"));
|
||||
}
|
||||
|
||||
static boolean tempDirCanBeOnDifferentRoot() {
|
||||
return isWindows;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="tempDirCanBeOnDifferentRoot", disabledReason="IllegalArgument 'other' has different root on GitHub Actions.")
|
||||
void shouldAcceptRelativeUserDataDir(@TempDir Path tmpDir) throws Exception {
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
Path cwd = Paths.get("").toAbsolutePath();
|
||||
Path relativePath = cwd.relativize(userDataDir);
|
||||
BrowserContext context = browserType.launchPersistentContext(relativePath);
|
||||
assertTrue(Files.list(userDataDir).count() > 0);
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class TestElementHandleSelectText extends TestBase {
|
||||
ElementHandle textarea = page.querySelector("textarea");
|
||||
textarea.evaluate("textarea => textarea.value = 'some value'");
|
||||
textarea.selectText();
|
||||
if (isFirefox() || isWebKit()) {
|
||||
if (isFirefox()) {
|
||||
assertEquals(0, textarea.evaluate("el => el.selectionStart"));
|
||||
assertEquals(10, textarea.evaluate("el => el.selectionEnd"));
|
||||
} else {
|
||||
@@ -42,7 +42,7 @@ public class TestElementHandleSelectText extends TestBase {
|
||||
ElementHandle input = page.querySelector("input");
|
||||
input.evaluate("input => input.value = 'some value'");
|
||||
input.selectText();
|
||||
if (isFirefox() || isWebKit()) {
|
||||
if (isFirefox()) {
|
||||
assertEquals(0, input.evaluate("el => el.selectionStart"));
|
||||
assertEquals(10, input.evaluate("el => el.selectionEnd"));
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user