Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4307548995 |
@@ -1,10 +1,6 @@
|
||||
trigger: none
|
||||
pr: none
|
||||
|
||||
trigger:
|
||||
tags:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
- repository: 1esPipelines
|
||||
@@ -37,8 +33,8 @@ extends:
|
||||
artifact: esrp-build
|
||||
steps:
|
||||
- bash: |
|
||||
if [[ ! "$CURRENT_BRANCH" =~ ^v1\..* ]]; then
|
||||
echo "Can only publish from a release tag branch (v1.*)."
|
||||
if [[ ! "$CURRENT_BRANCH" =~ ^release-.* ]]; then
|
||||
echo "Can only publish from a release branch."
|
||||
echo "Unexpected branch name: $CURRENT_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -20,19 +20,16 @@ jobs:
|
||||
test:
|
||||
name: Test
|
||||
timeout-minutes: 120
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [jammy, noble]
|
||||
runs-on: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
ARCH="${{ matrix.runs-on == 'ubuntu-24.04-arm' && 'arm64' || 'amd64' }}"
|
||||
bash utils/docker/build.sh --$ARCH ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
|
||||
run: bash utils/docker/build.sh --amd64 ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
|
||||
- name: Test
|
||||
run: |
|
||||
CONTAINER_ID="$(docker run --rm -e CI --ipc=host -v $(pwd):/root/playwright --name playwright-docker-test -d -t playwright-java:localbuild-${{ matrix.flavor }} /bin/bash)"
|
||||
CONTAINER_ID="$(docker run --rm --ipc=host -v $(pwd):/root/playwright --name playwright-docker-test -d -t playwright-java:localbuild-${{ matrix.flavor }} /bin/bash)"
|
||||
docker exec "${CONTAINER_ID}" /root/playwright/tools/test-local-installation/create_project_and_run_tests.sh
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
name: "Internal Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
name: "trigger"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- run: |
|
||||
curl -X POST \
|
||||
-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 }}
|
||||
@@ -1,3 +0,0 @@
|
||||
path_classifiers:
|
||||
tests:
|
||||
- "playwright/src/test/**"
|
||||
@@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->26.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->134.0.6998.35<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->18.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->135.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.54.0</version>
|
||||
<version>1.51.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.54.0</version>
|
||||
<version>1.51.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
|
||||
+2
-2
@@ -6,11 +6,11 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.54.0</version>
|
||||
<version>1.51.0</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<playwright.version>1.54.0</playwright.version>
|
||||
<playwright.version>1.51.0</playwright.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
+1
-10
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.54.0</version>
|
||||
<version>1.51.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
@@ -57,15 +57,6 @@
|
||||
<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>
|
||||
|
||||
@@ -72,12 +72,6 @@ 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.
|
||||
*/
|
||||
@@ -177,15 +171,6 @@ 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.
|
||||
*/
|
||||
|
||||
@@ -411,6 +411,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* 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.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> IndexedDBs with typed arrays are currently not supported.
|
||||
*/
|
||||
public Boolean indexedDB;
|
||||
/**
|
||||
@@ -423,6 +425,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* 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.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> IndexedDBs with typed arrays are currently not supported.
|
||||
*/
|
||||
public StorageStateOptions setIndexedDB(boolean indexedDB) {
|
||||
this.indexedDB = indexedDB;
|
||||
@@ -596,8 +600,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
List<Page> backgroundPages();
|
||||
/**
|
||||
* Gets the browser instance that owns the context. Returns {@code null} if the context is created outside of normal
|
||||
* browser, e.g. Android or Electron.
|
||||
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
@@ -872,7 +875,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* <li> {@code "notifications"}</li>
|
||||
* <li> {@code "payment-handler"}</li>
|
||||
* <li> {@code "storage-access"}</li>
|
||||
* <li> {@code "local-fonts"}</li>
|
||||
* </ul>
|
||||
* @since v1.8
|
||||
*/
|
||||
@@ -905,7 +907,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* <li> {@code "notifications"}</li>
|
||||
* <li> {@code "payment-handler"}</li>
|
||||
* <li> {@code "storage-access"}</li>
|
||||
* <li> {@code "local-fonts"}</li>
|
||||
* </ul>
|
||||
* @since v1.8
|
||||
*/
|
||||
@@ -995,8 +996,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1051,8 +1052,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1105,8 +1106,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1161,8 +1162,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1215,8 +1216,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -1271,8 +1272,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
|
||||
@@ -209,9 +209,6 @@ public interface BrowserType {
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
*
|
||||
* <p> You can also provide a path to a custom <a href="https://mozilla.github.io/policy-templates/">{@code policies.json}
|
||||
* file</a> via {@code PLAYWRIGHT_FIREFOX_POLICIES_JSON} environment variable.
|
||||
*/
|
||||
public Map<String, Object> firefoxUserPrefs;
|
||||
/**
|
||||
@@ -229,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://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public Boolean headless;
|
||||
/**
|
||||
@@ -342,9 +339,6 @@ public interface BrowserType {
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
*
|
||||
* <p> You can also provide a path to a custom <a href="https://mozilla.github.io/policy-templates/">{@code policies.json}
|
||||
* file</a> via {@code PLAYWRIGHT_FIREFOX_POLICIES_JSON} environment variable.
|
||||
*/
|
||||
public LaunchOptions setFirefoxUserPrefs(Map<String, Object> firefoxUserPrefs) {
|
||||
this.firefoxUserPrefs = firefoxUserPrefs;
|
||||
@@ -374,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://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public LaunchOptions setHeadless(boolean headless) {
|
||||
this.headless = headless;
|
||||
@@ -541,9 +535,6 @@ public interface BrowserType {
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
*
|
||||
* <p> You can also provide a path to a custom <a href="https://mozilla.github.io/policy-templates/">{@code policies.json}
|
||||
* file</a> via {@code PLAYWRIGHT_FIREFOX_POLICIES_JSON} environment variable.
|
||||
*/
|
||||
public Map<String, Object> firefoxUserPrefs;
|
||||
/**
|
||||
@@ -573,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://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public Boolean headless;
|
||||
/**
|
||||
@@ -890,9 +881,6 @@ public interface BrowserType {
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
*
|
||||
* <p> You can also provide a path to a custom <a href="https://mozilla.github.io/policy-templates/">{@code policies.json}
|
||||
* file</a> via {@code PLAYWRIGHT_FIREFOX_POLICIES_JSON} environment variable.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setFirefoxUserPrefs(Map<String, Object> firefoxUserPrefs) {
|
||||
this.firefoxUserPrefs = firefoxUserPrefs;
|
||||
@@ -946,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://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox</a>. Defaults to {@code true} unless
|
||||
* the {@code devtools} option is {@code true}.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
|
||||
* unless the {@code devtools} option is {@code true}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setHeadless(boolean headless) {
|
||||
this.headless = headless;
|
||||
@@ -1377,15 +1365,11 @@ 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. Pass an empty string to
|
||||
* create a temporary directory.
|
||||
*
|
||||
* <p> More details for <a
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
|
||||
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
|
||||
* href="https://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.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
|
||||
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
|
||||
* an empty string to use a temporary directory instead.
|
||||
* @since v1.8
|
||||
*/
|
||||
default BrowserContext launchPersistentContext(Path userDataDir) {
|
||||
@@ -1397,15 +1381,11 @@ 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. Pass an empty string to
|
||||
* create a temporary directory.
|
||||
*
|
||||
* <p> More details for <a
|
||||
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
|
||||
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
|
||||
* href="https://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.
|
||||
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
|
||||
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
|
||||
* an empty string to use a temporary directory instead.
|
||||
* @since v1.8
|
||||
*/
|
||||
BrowserContext launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options);
|
||||
|
||||
@@ -600,14 +600,18 @@ public interface Locator {
|
||||
}
|
||||
class EvaluateOptions {
|
||||
/**
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 EvaluateOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -616,14 +620,18 @@ public interface Locator {
|
||||
}
|
||||
class EvaluateHandleOptions {
|
||||
/**
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 EvaluateHandleOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -2602,20 +2610,6 @@ public interface Locator {
|
||||
* @since v1.14
|
||||
*/
|
||||
void dblclick(DblclickOptions options);
|
||||
/**
|
||||
* Describes the locator, description is used in the trace viewer and reports. Returns the locator pointing to the same
|
||||
* element.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Locator button = page.getByTestId("btn-sub").describe("Subscribe button");
|
||||
* button.click();
|
||||
* }</pre>
|
||||
*
|
||||
* @param description Locator description.
|
||||
* @since v1.53
|
||||
*/
|
||||
Locator describe(String description);
|
||||
/**
|
||||
* Programmatically dispatch an event on the matching element.
|
||||
*
|
||||
@@ -2862,14 +2856,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Passing argument to {@code expression}:
|
||||
* <pre>{@code
|
||||
* Object result = page.getByTestId("myId").evaluate("(element, [x, y]) => {\n" +
|
||||
* " return element.textContent + ' ' + x * y;\n" +
|
||||
* "}", Arrays.asList(7, 8));
|
||||
* System.out.println(result); // prints "myId text 56"
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
@@ -2894,14 +2880,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Passing argument to {@code expression}:
|
||||
* <pre>{@code
|
||||
* Object result = page.getByTestId("myId").evaluate("(element, [x, y]) => {\n" +
|
||||
* " return element.textContent + ' ' + x * y;\n" +
|
||||
* "}", Arrays.asList(7, 8));
|
||||
* System.out.println(result); // prints "myId text 56"
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.14
|
||||
@@ -2925,14 +2903,6 @@ public interface Locator {
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Passing argument to {@code expression}:
|
||||
* <pre>{@code
|
||||
* Object result = page.getByTestId("myId").evaluate("(element, [x, y]) => {\n" +
|
||||
* " return element.textContent + ' ' + x * y;\n" +
|
||||
* "}", Arrays.asList(7, 8));
|
||||
* System.out.println(result); // prints "myId text 56"
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
|
||||
@@ -21,11 +21,6 @@ import com.microsoft.playwright.options.*;
|
||||
/**
|
||||
* The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If you want to debug where the mouse moved, you can use the <a
|
||||
* href="https://playwright.dev/java/docs/trace-viewer-intro">Trace viewer</a> or <a
|
||||
* href="https://playwright.dev/java/docs/running-tests">Playwright Inspector</a>. A red dot showing the location of the
|
||||
* mouse will be shown for every mouse action.
|
||||
*
|
||||
* <p> Every {@code page} object has its own Mouse, accessible with {@link com.microsoft.playwright.Page#mouse Page.mouse()}.
|
||||
* <pre>{@code
|
||||
* // Using ‘page.mouse’ to trace a 100x100 square.
|
||||
|
||||
@@ -6317,8 +6317,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -6376,8 +6376,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -6433,8 +6433,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -6492,8 +6492,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -6549,8 +6549,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
@@ -6608,8 +6608,8 @@ public interface Page extends AutoCloseable {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @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
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
|
||||
* context options was provided and the passed URL is a path, it gets merged via the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
|
||||
* @param handler handler function to route the request.
|
||||
* @since v1.8
|
||||
|
||||
@@ -370,10 +370,6 @@ public interface Route {
|
||||
* 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
|
||||
*/
|
||||
default void resume() {
|
||||
@@ -402,10 +398,6 @@ public interface Route {
|
||||
* 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);
|
||||
|
||||
@@ -23,12 +23,6 @@ import java.nio.file.Path;
|
||||
* API for collecting and saving Playwright traces. Playwright traces can be opened in <a
|
||||
* href="https://playwright.dev/java/docs/trace-viewer">Trace Viewer</a> after Playwright script runs.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> You probably want to <a href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enable tracing in
|
||||
* your config file</a> instead of using {@code context.tracing}.The {@code context.tracing} API captures browser operations and network activity, but it doesn't record test assertions
|
||||
* (like {@code expect} calls). We recommend <a
|
||||
* href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enabling tracing through Playwright Test
|
||||
* configuration</a>, which includes those assertions and provides a more complete trace for debugging test failures.
|
||||
*
|
||||
* <p> Start recording a trace before performing actions. At the end, stop tracing and save it to a file.
|
||||
* <pre>{@code
|
||||
* Browser browser = chromium.launch();
|
||||
@@ -206,12 +200,6 @@ public interface Tracing {
|
||||
/**
|
||||
* Start tracing.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> You probably want to <a href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enable tracing in
|
||||
* your config file</a> instead of using {@code Tracing.start}.The {@code context.tracing} API captures browser operations and network activity, but it doesn't record test assertions
|
||||
* (like {@code expect} calls). We recommend <a
|
||||
* href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enabling tracing through Playwright Test
|
||||
* configuration</a>, which includes those assertions and provides a more complete trace for debugging test failures.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
@@ -231,12 +219,6 @@ public interface Tracing {
|
||||
/**
|
||||
* Start tracing.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> You probably want to <a href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enable tracing in
|
||||
* your config file</a> instead of using {@code Tracing.start}.The {@code context.tracing} API captures browser operations and network activity, but it doesn't record test assertions
|
||||
* (like {@code expect} calls). We recommend <a
|
||||
* href="https://playwright.dev/docs/api/class-testoptions#test-options-trace">enabling tracing through Playwright Test
|
||||
* configuration</a>, which includes those assertions and provides a more complete trace for debugging test failures.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.function.Consumer;
|
||||
*
|
||||
* <p> <strong>Mocking</strong>
|
||||
*
|
||||
* <p> By default, the routed WebSocket will not connect to the server. This way, you can mock entire communication over the
|
||||
* <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 -> {
|
||||
|
||||
+24
-139
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
@@ -238,20 +237,6 @@ 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
|
||||
@@ -870,98 +855,6 @@ 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.
|
||||
@@ -1552,20 +1445,19 @@ public interface LocatorAssertions {
|
||||
void hasAttribute(String name, Pattern value, HasAttributeOptions options);
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1576,20 +1468,19 @@ public interface LocatorAssertions {
|
||||
}
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1598,20 +1489,19 @@ public interface LocatorAssertions {
|
||||
void hasClass(String expected, HasClassOptions options);
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1622,20 +1512,19 @@ public interface LocatorAssertions {
|
||||
}
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1644,20 +1533,19 @@ public interface LocatorAssertions {
|
||||
void hasClass(Pattern expected, HasClassOptions options);
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1668,20 +1556,19 @@ public interface LocatorAssertions {
|
||||
}
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1690,20 +1577,19 @@ public interface LocatorAssertions {
|
||||
void hasClass(String[] expected, HasClassOptions options);
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
@@ -1714,20 +1600,19 @@ public interface LocatorAssertions {
|
||||
}
|
||||
/**
|
||||
* 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()}.
|
||||
* the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
|
||||
* assertThat(page.locator("#component")).hasClass("middle selected row");
|
||||
* }</pre>
|
||||
*
|
||||
* <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"});
|
||||
* assertThat(page.locator("list > .component")).hasClass(new String[] {"component", "component selected", "component"});
|
||||
* }</pre>
|
||||
*
|
||||
* @param expected Expected class or RegExp or a list of those.
|
||||
|
||||
@@ -39,8 +39,6 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
private final TracingImpl tracing;
|
||||
private String disposeReason;
|
||||
|
||||
protected TimeoutSettings timeoutSettings = new TimeoutSettings();
|
||||
|
||||
APIRequestContextImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this.tracing = connection.getExistingObject(initializer.getAsJsonObject("tracing").get("guid").getAsString());
|
||||
@@ -53,17 +51,21 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
|
||||
@Override
|
||||
public void dispose(DisposeOptions options) {
|
||||
withLogging("APIRequestContext.dispose", () -> disposeImpl(options));
|
||||
}
|
||||
|
||||
private void disposeImpl(DisposeOptions options) {
|
||||
if (options == null) {
|
||||
options = new DisposeOptions();
|
||||
}
|
||||
disposeReason = options.reason;
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("dispose", params, NO_TIMEOUT);
|
||||
sendMessage("dispose", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse fetch(String urlOrRequest, RequestOptions options) {
|
||||
return fetchImpl(urlOrRequest, (RequestOptionsImpl) options);
|
||||
return withLogging("APIRequestContext.fetch", () -> fetchImpl(urlOrRequest, (RequestOptionsImpl) options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,7 +93,6 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
if (options == null) {
|
||||
options = new RequestOptionsImpl();
|
||||
}
|
||||
options.timeout = timeoutSettings.timeout(options.timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("url", url);
|
||||
if (options.params != null) {
|
||||
@@ -131,6 +132,9 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
if (options.multipart != null) {
|
||||
params.add("multipartData", serializeMultipartData(options.multipart.fields));
|
||||
}
|
||||
if (options.timeout != null) {
|
||||
params.addProperty("timeout", options.timeout);
|
||||
}
|
||||
if (options.failOnStatusCode != null) {
|
||||
params.addProperty("failOnStatusCode", options.failOnStatusCode);
|
||||
}
|
||||
@@ -149,7 +153,7 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
}
|
||||
params.addProperty("maxRetries", options.maxRetries);
|
||||
}
|
||||
JsonObject json = sendMessage("fetch", params, timeoutSettings.timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("fetch", params).getAsJsonObject();
|
||||
return new APIResponseImpl(this, json.getAsJsonObject("response"));
|
||||
}
|
||||
|
||||
@@ -215,12 +219,14 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
|
||||
@Override
|
||||
public String storageState(StorageStateOptions options) {
|
||||
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("APIRequestContext.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;
|
||||
});
|
||||
}
|
||||
|
||||
private static RequestOptionsImpl ensureOptions(RequestOptions options, String method) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
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;
|
||||
@@ -25,11 +26,12 @@ 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.ChannelOwner.NO_TIMEOUT;
|
||||
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;
|
||||
@@ -40,6 +42,10 @@ class APIRequestImpl implements APIRequest {
|
||||
|
||||
@Override
|
||||
public APIRequestContextImpl newContext(NewContextOptions options) {
|
||||
return playwright.withLogging("APIRequest.newContext", () -> newContextImpl(options));
|
||||
}
|
||||
|
||||
private APIRequestContextImpl newContextImpl(NewContextOptions options) {
|
||||
if (options == null) {
|
||||
options = new NewContextOptions();
|
||||
} else {
|
||||
@@ -61,17 +67,13 @@ class APIRequestImpl implements APIRequest {
|
||||
}
|
||||
List<ClientCertificate> clientCertificateList = options.clientCertificates;
|
||||
options.clientCertificates = null;
|
||||
Double timeout = options.timeout;
|
||||
// Timeout is handled on the client.
|
||||
options.timeout = null;
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (storageState != null) {
|
||||
params.add("storageState", storageState);
|
||||
}
|
||||
addToProtocol(params, clientCertificateList);
|
||||
JsonObject result = playwright.sendMessage("newRequest", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = playwright.sendMessage("newRequest", params).getAsJsonObject();
|
||||
APIRequestContextImpl context = playwright.connection.getExistingObject(result.getAsJsonObject("request").get("guid").getAsString());
|
||||
context.timeoutSettings.setDefaultTimeout(timeout);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
@@ -28,7 +29,6 @@ import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
|
||||
import static java.util.Arrays.asList;
|
||||
@@ -49,7 +49,7 @@ class APIResponseImpl implements APIResponse {
|
||||
try {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchResponseBody", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = context.sendMessage("fetchResponseBody", params).getAsJsonObject();
|
||||
if (!json.has("binary")) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
@@ -64,9 +64,11 @@ class APIResponseImpl implements APIResponse {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
context.sendMessage("disposeAPIResponse", params, NO_TIMEOUT);
|
||||
context.withLogging("APIResponse.dispose", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
context.sendMessage("disposeAPIResponse", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,7 +114,7 @@ class APIResponseImpl implements APIResponse {
|
||||
List<String> fetchLog() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchLog", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = context.sendMessage("fetchLog", params).getAsJsonObject();
|
||||
JsonArray log = json.get("log").getAsJsonArray();
|
||||
return gson().fromJson(log, new TypeToken<List<String>>() {}.getType());
|
||||
}
|
||||
|
||||
@@ -86,6 +86,6 @@ class ArtifactImpl extends ChannelOwner {
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("path", path.toString());
|
||||
sendMessage("saveAs", params, NO_TIMEOUT);
|
||||
sendMessage("saveAs", params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
import org.opentest4j.ValueWrapper;
|
||||
|
||||
@@ -28,26 +29,28 @@ import java.util.stream.Collectors;
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
abstract class AssertionsBase {
|
||||
class AssertionsBase {
|
||||
final LocatorImpl actualLocator;
|
||||
final boolean isNot;
|
||||
|
||||
AssertionsBase(boolean isNot) {
|
||||
AssertionsBase(LocatorImpl actual, boolean isNot) {
|
||||
this.actualLocator = actual;
|
||||
this.isNot = isNot;
|
||||
}
|
||||
|
||||
void expectImpl(String expression, ExpectedTextValue textValue, Object expected, String message, FrameExpectOptions options, String title) {
|
||||
expectImpl(expression, asList(textValue), expected, message, options, title);
|
||||
void expectImpl(String expression, ExpectedTextValue textValue, Object expected, String message, FrameExpectOptions options) {
|
||||
expectImpl(expression, asList(textValue), expected, message, options);
|
||||
}
|
||||
|
||||
void expectImpl(String expression, List<ExpectedTextValue> expectedText, Object expected, String message, FrameExpectOptions options, String title) {
|
||||
void expectImpl(String expression, List<ExpectedTextValue> expectedText, Object expected, String message, FrameExpectOptions options) {
|
||||
if (options == null) {
|
||||
options = new FrameExpectOptions();
|
||||
}
|
||||
options.expectedText = expectedText;
|
||||
expectImpl(expression, options, expected, message, title);
|
||||
expectImpl(expression, options, expected, message);
|
||||
}
|
||||
|
||||
void expectImpl(String expression, FrameExpectOptions expectOptions, Object expected, String message, String title) {
|
||||
void expectImpl(String expression, FrameExpectOptions expectOptions, Object expected, String message) {
|
||||
if (expectOptions.timeout == null) {
|
||||
expectOptions.timeout = AssertionsTimeout.defaultTimeout;
|
||||
}
|
||||
@@ -55,7 +58,7 @@ abstract class AssertionsBase {
|
||||
if (isNot) {
|
||||
message = message.replace("expected to", "expected not to");
|
||||
}
|
||||
FrameExpectResult result = doExpect(expression, expectOptions, title);
|
||||
FrameExpectResult result = actualLocator.expect(expression, expectOptions);
|
||||
if (result.matches == isNot) {
|
||||
Object actual = result.received == null ? null : Serialization.deserialize(result.received);
|
||||
String log = (result.log == null) ? "" : String.join("\n", result.log);
|
||||
@@ -72,9 +75,7 @@ abstract class AssertionsBase {
|
||||
}
|
||||
}
|
||||
|
||||
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);
|
||||
|
||||
protected static ValueWrapper formatValue(Object value) {
|
||||
private static ValueWrapper formatValue(Object value) {
|
||||
if (value == null || !value.getClass().isArray()) {
|
||||
return ValueWrapper.create(value);
|
||||
}
|
||||
|
||||
@@ -78,11 +78,11 @@ class BindingCall extends ChannelOwner {
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("result", gson().toJsonTree(serializeArgument(result)));
|
||||
sendMessage("resolve", params, NO_TIMEOUT);
|
||||
sendMessage("resolve", params);
|
||||
} catch (RuntimeException exception) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("error", gson().toJsonTree(serializeError(exception)));
|
||||
sendMessage("reject", params, NO_TIMEOUT);
|
||||
sendMessage("reject", params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import static java.nio.file.Files.readAllBytes;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
protected BrowserImpl browser;
|
||||
private final BrowserImpl browser;
|
||||
private final TracingImpl tracing;
|
||||
private final APIRequestContextImpl request;
|
||||
private final ClockImpl clock;
|
||||
@@ -51,7 +51,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
final Router routes = new Router();
|
||||
final WebSocketRouter webSocketRoutes = new WebSocketRouter();
|
||||
private boolean closingOrClosed;
|
||||
private boolean closeWasCalled;
|
||||
private final WaitableEvent<EventType, ?> closePromise;
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
PageImpl ownerPage;
|
||||
@@ -69,6 +69,8 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>(eventSubscriptions(), this);
|
||||
final TimeoutSettings timeoutSettings = new TimeoutSettings();
|
||||
Path videosDir;
|
||||
URL baseUrl;
|
||||
final Map<String, HarRecorder> harRecorders = new HashMap<>();
|
||||
|
||||
static class HarRecorder {
|
||||
@@ -96,30 +98,29 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
BrowserContextImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
if (parent instanceof BrowserImpl) {
|
||||
browser = (BrowserImpl) parent;
|
||||
} else {
|
||||
browser = null;
|
||||
}
|
||||
tracing = connection.getExistingObject(initializer.getAsJsonObject("tracing").get("guid").getAsString());
|
||||
request = connection.getExistingObject(initializer.getAsJsonObject("requestContext").get("guid").getAsString());
|
||||
request.timeoutSettings = timeoutSettings;
|
||||
clock = new ClockImpl(this);
|
||||
closePromise = new WaitableEvent<>(listeners, EventType.CLOSE);
|
||||
}
|
||||
|
||||
Path videosDir() {
|
||||
JsonObject recordVideo = initializer.getAsJsonObject("options").getAsJsonObject("recordVideo");
|
||||
if (recordVideo == null) {
|
||||
return null;
|
||||
void setRecordHar(Path path, HarContentPolicy policy) {
|
||||
if (path != null) {
|
||||
harRecorders.put("", new HarRecorder(path, policy));
|
||||
}
|
||||
return Paths.get(recordVideo.get("dir").getAsString());
|
||||
}
|
||||
|
||||
URL baseUrl() {
|
||||
JsonElement url = initializer.getAsJsonObject("options").get("baseURL");
|
||||
if (url != null) {
|
||||
try {
|
||||
return new URL(url.getAsString());
|
||||
} catch (MalformedURLException e) {
|
||||
}
|
||||
void setBaseUrl(String spec) {
|
||||
try {
|
||||
this.baseUrl = new URL(spec);
|
||||
} catch (MalformedURLException e) {
|
||||
this.baseUrl = null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String effectiveCloseReason() {
|
||||
@@ -261,7 +262,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
public CDPSession newCDPSession(Page page) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("page", ((PageImpl) page).toProtocolRef());
|
||||
JsonObject result = sendMessage("newCDPSession", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = sendMessage("newCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@@ -269,14 +270,23 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
public CDPSession newCDPSession(Frame frame) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("frame", ((FrameImpl) frame).toProtocolRef());
|
||||
JsonObject result = sendMessage("newCDPSession", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = sendMessage("newCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
if (!closingOrClosed) {
|
||||
closingOrClosed = true;
|
||||
withLogging("BrowserContext.close", () -> closeImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> cookies(String url) {
|
||||
return cookies(url == null ? new ArrayList<>() : Collections.singletonList(url));
|
||||
}
|
||||
|
||||
private void closeImpl(CloseOptions options) {
|
||||
if (!closeWasCalled) {
|
||||
closeWasCalled = true;
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
@@ -285,7 +295,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
for (Map.Entry<String, HarRecorder> entry : harRecorders.entrySet()) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("harId", entry.getKey());
|
||||
JsonObject json = sendMessage("harExport", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("harExport", params).getAsJsonObject();
|
||||
ArtifactImpl artifact = connection.getExistingObject(json.getAsJsonObject("artifact").get("guid").getAsString());
|
||||
// Server side will compress artifact if content is attach or if file is .zip.
|
||||
HarRecorder harParams = entry.getValue();
|
||||
@@ -297,46 +307,42 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
JsonObject unzipParams = new JsonObject();
|
||||
unzipParams.addProperty("zipFile", tmpPath);
|
||||
unzipParams.addProperty("harFile", harParams.path.toString());
|
||||
connection.localUtils.sendMessage("harUnzip", unzipParams, NO_TIMEOUT);
|
||||
connection.localUtils.sendMessage("harUnzip", unzipParams);
|
||||
} else {
|
||||
artifact.saveAs(harParams.path);
|
||||
}
|
||||
artifact.delete();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("close", params, NO_TIMEOUT);
|
||||
sendMessage("close", params);
|
||||
}
|
||||
runUntil(() -> {}, closePromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> cookies(String url) {
|
||||
return cookies(url == null ? new ArrayList<>() : Collections.singletonList(url));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCookies(List<Cookie> cookies) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("cookies", gson().toJsonTree(cookies));
|
||||
sendMessage("addCookies", params, NO_TIMEOUT);
|
||||
withLogging("BrowserContext.addCookies", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("cookies", gson().toJsonTree(cookies));
|
||||
sendMessage("addCookies", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInitScript(String script) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("source", script);
|
||||
sendMessage("addInitScript", params, NO_TIMEOUT);
|
||||
withLogging("BrowserContext.addInitScript", () -> addInitScriptImpl(script));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInitScript(Path path) {
|
||||
try {
|
||||
byte[] bytes = readAllBytes(path);
|
||||
addInitScript(new String(bytes, UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read script from file", e);
|
||||
}
|
||||
withLogging("BrowserContext.addInitScript", () -> {
|
||||
try {
|
||||
byte[] bytes = readAllBytes(path);
|
||||
addInitScriptImpl(new String(bytes, UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read script from file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -344,6 +350,12 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
return new ArrayList<>(backgroundPages);
|
||||
}
|
||||
|
||||
private void addInitScriptImpl(String script) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("source", script);
|
||||
sendMessage("addInitScript", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrowserImpl browser() {
|
||||
return browser;
|
||||
@@ -351,6 +363,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void clearCookies(ClearCookiesOptions options) {
|
||||
withLogging("BrowserContext.clearCookies", () -> clearCookiesImpl(options));
|
||||
}
|
||||
|
||||
private void clearCookiesImpl(ClearCookiesOptions options) {
|
||||
if (options == null) {
|
||||
options = new ClearCookiesOptions();
|
||||
}
|
||||
@@ -358,7 +374,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
setStringOrRegex(params, "name", options.name);
|
||||
setStringOrRegex(params, "domain", options.domain);
|
||||
setStringOrRegex(params, "path", options.path);
|
||||
sendMessage("clearCookies", params, NO_TIMEOUT);
|
||||
sendMessage("clearCookies", params);
|
||||
}
|
||||
|
||||
private static void setStringOrRegex(JsonObject params, String name, Object value) {
|
||||
@@ -373,24 +389,28 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void clearPermissions() {
|
||||
sendMessage("clearPermissions");
|
||||
withLogging("BrowserContext.clearPermissions", () -> sendMessage("clearPermissions"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> cookies(List<String> urls) {
|
||||
return withLogging("BrowserContext.cookies", () -> cookiesImpl(urls));
|
||||
}
|
||||
|
||||
private List<Cookie> cookiesImpl(List<String> urls) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (urls == null) {
|
||||
urls = new ArrayList<>();
|
||||
}
|
||||
params.add("urls", gson().toJsonTree(urls));
|
||||
JsonObject json = sendMessage("cookies", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("cookies", params).getAsJsonObject();
|
||||
Cookie[] cookies = gson().fromJson(json.getAsJsonArray("cookies"), Cookie[].class);
|
||||
return asList(cookies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeBinding(String name, BindingCallback playwrightBinding, ExposeBindingOptions options) {
|
||||
exposeBindingImpl(name, playwrightBinding, options);
|
||||
withLogging("BrowserContext.exposeBinding", () -> exposeBindingImpl(name, playwrightBinding, options));
|
||||
}
|
||||
|
||||
private void exposeBindingImpl(String name, BindingCallback playwrightBinding, ExposeBindingOptions options) {
|
||||
@@ -409,16 +429,21 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
if (options != null && options.handle != null && options.handle) {
|
||||
params.addProperty("needsHandle", true);
|
||||
}
|
||||
sendMessage("exposeBinding", params, NO_TIMEOUT);
|
||||
sendMessage("exposeBinding", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeFunction(String name, FunctionCallback playwrightFunction) {
|
||||
exposeBindingImpl(name, (BindingCallback.Source source, Object... args) -> playwrightFunction.call(args), null);
|
||||
withLogging("BrowserContext.exposeFunction",
|
||||
() -> exposeBindingImpl(name, (BindingCallback.Source source, Object... args) -> playwrightFunction.call(args), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantPermissions(List<String> permissions, GrantPermissionsOptions options) {
|
||||
withLogging("BrowserContext.grantPermissions", () -> grantPermissionsImpl(permissions, options));
|
||||
}
|
||||
|
||||
private void grantPermissionsImpl(List<String> permissions, GrantPermissionsOptions options) {
|
||||
if (options == null) {
|
||||
options = new GrantPermissionsOptions();
|
||||
}
|
||||
@@ -427,11 +452,15 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.add("permissions", gson().toJsonTree(permissions));
|
||||
sendMessage("grantPermissions", params, NO_TIMEOUT);
|
||||
sendMessage("grantPermissions", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageImpl newPage() {
|
||||
return withLogging("BrowserContext.newPage", () -> newPageImpl());
|
||||
}
|
||||
|
||||
private PageImpl newPageImpl() {
|
||||
if (ownerPage != null) {
|
||||
throw new PlaywrightException("Please use browser.newContext()");
|
||||
}
|
||||
@@ -451,7 +480,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void route(String url, Consumer<Route> handler, RouteOptions options) {
|
||||
route(UrlMatcher.forGlob(baseUrl(), url, this.connection.localUtils, false), handler, options);
|
||||
route(new UrlMatcher(baseUrl, url), handler, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -470,23 +499,25 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
options = new RouteFromHAROptions();
|
||||
}
|
||||
if (options.update != null && options.update) {
|
||||
recordIntoHar(null, har, options, null);
|
||||
recordIntoHar(null, har, options);
|
||||
return;
|
||||
}
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(baseUrl(), options.url, this.connection.localUtils, false);
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(baseUrl, options.url);
|
||||
HARRouter harRouter = new HARRouter(connection.localUtils, har, options.notFound);
|
||||
onClose(context -> harRouter.dispose());
|
||||
route(matcher, route -> harRouter.handle(route), null);
|
||||
}
|
||||
|
||||
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
withLogging("BrowserContext.route", () -> {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(String url, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(UrlMatcher.forGlob(baseUrl(), url, this.connection.localUtils, true), handler);
|
||||
routeWebSocketImpl(new UrlMatcher(baseUrl, url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -500,82 +531,108 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
|
||||
private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
withLogging("BrowserContext.routeWebSocket", () -> {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options, HarContentPolicy contentPolicy) {
|
||||
if (contentPolicy == null) {
|
||||
contentPolicy = Utils.convertType(options.updateContent, HarContentPolicy.class);
|
||||
}
|
||||
if (contentPolicy == null) {
|
||||
contentPolicy = HarContentPolicy.ATTACH;
|
||||
}
|
||||
|
||||
void recordIntoHar(PageImpl page, Path har, RouteFromHAROptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (page != null) {
|
||||
params.add("page", page.toProtocolRef());
|
||||
}
|
||||
JsonObject recordHarArgs = new JsonObject();
|
||||
recordHarArgs.addProperty("zip", har.toString().endsWith(".zip"));
|
||||
recordHarArgs.addProperty("content", contentPolicy.name().toLowerCase());
|
||||
recordHarArgs.addProperty("mode", (options.updateMode == null ? HarMode.MINIMAL : options.updateMode).name().toLowerCase());
|
||||
addHarUrlFilter(recordHarArgs, options.url);
|
||||
|
||||
params.add("options", recordHarArgs);
|
||||
JsonObject json = sendMessage("harStart", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject jsonOptions = new JsonObject();
|
||||
jsonOptions.addProperty("path", har.toAbsolutePath().toString());
|
||||
jsonOptions.addProperty("content", options.updateContent == null ?
|
||||
HarContentPolicy.ATTACH.name().toLowerCase() :
|
||||
options.updateContent.name().toLowerCase());
|
||||
jsonOptions.addProperty("mode", options.updateMode == null ?
|
||||
HarMode.MINIMAL.name().toLowerCase() :
|
||||
options.updateMode.name().toLowerCase());
|
||||
addHarUrlFilter(jsonOptions, options.url);
|
||||
params.add("options", jsonOptions);
|
||||
JsonObject json = sendMessage("harStart", params).getAsJsonObject();
|
||||
String harId = json.get("harId").getAsString();
|
||||
harRecorders.put(harId, new HarRecorder(har, contentPolicy));
|
||||
harRecorders.put(harId, new HarRecorder(har, HarContentPolicy.ATTACH));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultNavigationTimeout(double timeout) {
|
||||
timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
setDefaultNavigationTimeoutImpl(timeout);
|
||||
}
|
||||
|
||||
void setDefaultNavigationTimeoutImpl(Double timeout) {
|
||||
withLogging("BrowserContext.setDefaultNavigationTimeout", () -> {
|
||||
timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeout", timeout);
|
||||
sendMessage("setDefaultNavigationTimeoutNoReply", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultTimeout(double timeout) {
|
||||
timeoutSettings.setDefaultTimeout(timeout);
|
||||
setDefaultTimeoutImpl(timeout);
|
||||
}
|
||||
|
||||
void setDefaultTimeoutImpl(Double timeout) {
|
||||
withLogging("BrowserContext.setDefaultTimeout", () -> {
|
||||
timeoutSettings.setDefaultTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeout", timeout);
|
||||
sendMessage("setDefaultTimeoutNoReply", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraHTTPHeaders(Map<String, String> headers) {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonArray jsonHeaders = new JsonArray();
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
JsonObject header = new JsonObject();
|
||||
header.addProperty("name", e.getKey());
|
||||
header.addProperty("value", e.getValue());
|
||||
jsonHeaders.add(header);
|
||||
}
|
||||
params.add("headers", jsonHeaders);
|
||||
sendMessage("setExtraHTTPHeaders", params, NO_TIMEOUT);
|
||||
withLogging("BrowserContext.setExtraHTTPHeaders", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonArray jsonHeaders = new JsonArray();
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
JsonObject header = new JsonObject();
|
||||
header.addProperty("name", e.getKey());
|
||||
header.addProperty("value", e.getValue());
|
||||
jsonHeaders.add(header);
|
||||
}
|
||||
params.add("headers", jsonHeaders);
|
||||
sendMessage("setExtraHTTPHeaders", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeolocation(Geolocation geolocation) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (geolocation != null) {
|
||||
params.add("geolocation", gson().toJsonTree(geolocation));
|
||||
}
|
||||
sendMessage("setGeolocation", params, NO_TIMEOUT);
|
||||
withLogging("BrowserContext.setGeolocation", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
if (geolocation != null) {
|
||||
params.add("geolocation", gson().toJsonTree(geolocation));
|
||||
}
|
||||
sendMessage("setGeolocation", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffline(boolean offline) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("offline", offline);
|
||||
sendMessage("setOffline", params, NO_TIMEOUT);
|
||||
withLogging("BrowserContext.setOffline", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("offline", offline);
|
||||
sendMessage("setOffline", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String storageState(StorageStateOptions options) {
|
||||
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, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("storageState", params);
|
||||
|
||||
String storageState = json.toString();
|
||||
if (options.path != null) {
|
||||
@@ -591,13 +648,15 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void unrouteAll() {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
withLogging("BrowserContext.unrouteAll", () -> {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(UrlMatcher.forGlob(this.baseUrl(), url, this.connection.localUtils, false), handler);
|
||||
unroute(new UrlMatcher(this.baseUrl, url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -643,16 +702,18 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
|
||||
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
withLogging("BrowserContext.unroute", () -> {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInterceptionPatterns() {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns(), NO_TIMEOUT);
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
}
|
||||
|
||||
private void updateWebSocketInterceptionPatterns() {
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns(), NO_TIMEOUT);
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns());
|
||||
}
|
||||
|
||||
void handleRoute(RouteImpl route) {
|
||||
@@ -805,10 +866,8 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
|
||||
void didClose() {
|
||||
closingOrClosed = true;
|
||||
if (browser != null) {
|
||||
browser.contexts.remove(this);
|
||||
browser.browserType.playwright.selectors.contextsForSelectors.remove(this);
|
||||
}
|
||||
listeners.notify(EventType.CLOSE, this);
|
||||
}
|
||||
@@ -817,49 +876,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
params.addProperty("lastModifiedMs", lastModifiedMs);
|
||||
JsonObject json = sendMessage("createTempFile", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("createTempFile", params).getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("writableStream").get("guid").getAsString());
|
||||
}
|
||||
|
||||
protected void initializeHarFromOptions(Browser.NewContextOptions options) {
|
||||
if (options.recordHarPath == null) {
|
||||
if (options.recordHarOmitContent != null) {
|
||||
throw new PlaywrightException("recordHarOmitContent is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarUrlFilter != null) {
|
||||
throw new PlaywrightException("recordHarUrlFilter is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarMode != null) {
|
||||
throw new PlaywrightException("recordHarMode is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarContent != null) {
|
||||
throw new PlaywrightException("recordHarContent is set but recordHarPath is null");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
HarContentPolicy contentPolicy = options.recordHarContent;
|
||||
if (contentPolicy == null && options.recordHarOmitContent != null && options.recordHarOmitContent == true) {
|
||||
contentPolicy = HarContentPolicy.OMIT;
|
||||
}
|
||||
if (contentPolicy == null) {
|
||||
contentPolicy = options.recordHarPath.endsWith(".zip") ? HarContentPolicy.ATTACH : HarContentPolicy.EMBED;
|
||||
}
|
||||
RouteFromHAROptions routeFromHAROptions = new RouteFromHAROptions();
|
||||
|
||||
if (options.recordHarUrlFilter instanceof String) {
|
||||
routeFromHAROptions.setUrl((String) options.recordHarUrlFilter);
|
||||
} else if (options.recordHarUrlFilter instanceof Pattern) {
|
||||
routeFromHAROptions.setUrl((Pattern) options.recordHarUrlFilter);
|
||||
}
|
||||
|
||||
if (options.recordHarMode != null) {
|
||||
routeFromHAROptions.updateMode = options.recordHarMode;
|
||||
} else {
|
||||
routeFromHAROptions.updateMode = HarMode.FULL;
|
||||
}
|
||||
routeFromHAROptions.url = options.recordHarUrlFilter;
|
||||
|
||||
recordIntoHar(null, options.recordHarPath, routeFromHAROptions, contentPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.HarContentPolicy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -28,8 +29,10 @@ import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
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.*;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
class BrowserImpl extends ChannelOwner implements Browser {
|
||||
final Set<BrowserContextImpl> contexts = new HashSet<>();
|
||||
@@ -66,6 +69,10 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
withLogging("Browser.close", () -> closeImpl(options));
|
||||
}
|
||||
|
||||
private void closeImpl(CloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
@@ -110,20 +117,16 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
|
||||
@Override
|
||||
public BrowserContextImpl newContext(NewContextOptions options) {
|
||||
return withLogging("Browser.newContext", () -> newContextImpl(options));
|
||||
}
|
||||
|
||||
private BrowserContextImpl newContextImpl(NewContextOptions options) {
|
||||
if (options == null) {
|
||||
options = new NewContextOptions();
|
||||
} else {
|
||||
// Make a copy so that we can nullify some fields below.
|
||||
options = convertType(options, NewContextOptions.class);
|
||||
}
|
||||
|
||||
NewContextOptions harOptions = Utils.clone(options);
|
||||
options.recordHarContent = null;
|
||||
options.recordHarMode = null;
|
||||
options.recordHarPath = null;
|
||||
options.recordHarOmitContent = null;
|
||||
options.recordHarUrlFilter = null;
|
||||
|
||||
if (options.storageStatePath != null) {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(options.storageStatePath);
|
||||
@@ -138,10 +141,51 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
storageState = new Gson().fromJson(options.storageState, JsonObject.class);
|
||||
options.storageState = null;
|
||||
}
|
||||
JsonObject recordHar = null;
|
||||
Path recordHarPath = options.recordHarPath;
|
||||
HarContentPolicy harContentPolicy = null;
|
||||
if (options.recordHarPath != null) {
|
||||
recordHar = new JsonObject();
|
||||
recordHar.addProperty("path", options.recordHarPath.toString());
|
||||
if (options.recordHarContent != null) {
|
||||
harContentPolicy = options.recordHarContent;
|
||||
} else if (options.recordHarOmitContent != null && options.recordHarOmitContent) {
|
||||
harContentPolicy = HarContentPolicy.OMIT;
|
||||
}
|
||||
if (harContentPolicy != null) {
|
||||
recordHar.addProperty("content", harContentPolicy.name().toLowerCase());
|
||||
}
|
||||
if (options.recordHarMode != null) {
|
||||
recordHar.addProperty("mode", options.recordHarMode.name().toLowerCase());
|
||||
}
|
||||
addHarUrlFilter(recordHar, options.recordHarUrlFilter);
|
||||
options.recordHarPath = null;
|
||||
options.recordHarMode = null;
|
||||
options.recordHarOmitContent = null;
|
||||
options.recordHarContent = null;
|
||||
options.recordHarUrlFilter = null;
|
||||
} else {
|
||||
if (options.recordHarOmitContent != null) {
|
||||
throw new PlaywrightException("recordHarOmitContent is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarUrlFilter != null) {
|
||||
throw new PlaywrightException("recordHarUrlFilter is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarMode != null) {
|
||||
throw new PlaywrightException("recordHarMode is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarContent != null) {
|
||||
throw new PlaywrightException("recordHarContent is set but recordHarPath is null");
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (storageState != null) {
|
||||
params.add("storageState", storageState);
|
||||
}
|
||||
if (recordHar != null) {
|
||||
params.add("recordHar", recordHar);
|
||||
}
|
||||
if (options.recordVideoDir != null) {
|
||||
JsonObject recordVideo = new JsonObject();
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toAbsolutePath().toString());
|
||||
@@ -169,21 +213,31 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
}
|
||||
params.add("selectorEngines", gson().toJsonTree(browserType.playwright.selectors.selectorEngines));
|
||||
params.addProperty("testIdAttributeName", browserType.playwright.selectors.testIdAttributeName);
|
||||
JsonElement result = sendMessage("newContext", params, NO_TIMEOUT);
|
||||
JsonElement result = sendMessage("newContext", params);
|
||||
BrowserContextImpl context = connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("context").get("guid").getAsString());
|
||||
context.initializeHarFromOptions(harOptions);
|
||||
context.videosDir = options.recordVideoDir;
|
||||
if (options.baseURL != null) {
|
||||
context.setBaseUrl(options.baseURL);
|
||||
}
|
||||
context.setRecordHar(recordHarPath, harContentPolicy);
|
||||
if (launchOptions != null) {
|
||||
context.tracing().setTracesDir(launchOptions.tracesDir);
|
||||
}
|
||||
contexts.add(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page newPage(NewPageOptions options) {
|
||||
return withTitle("Create Page", () -> newPageImpl(options));
|
||||
return withLogging("Browser.newPage", () -> newPageImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTracing(Page page, StartTracingOptions options) {
|
||||
withLogging("Browser.startTracing", () -> startTracingImpl(page, options));
|
||||
}
|
||||
|
||||
private void startTracingImpl(Page page, StartTracingOptions options) {
|
||||
if (options == null) {
|
||||
options = new StartTracingOptions();
|
||||
}
|
||||
@@ -192,11 +246,15 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
if (page != null) {
|
||||
params.add("page", ((PageImpl) page).toProtocolRef());
|
||||
}
|
||||
sendMessage("startTracing", params, NO_TIMEOUT);
|
||||
sendMessage("startTracing", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] stopTracing() {
|
||||
return withLogging("Browser.stopTracing", () -> stopTracingImpl());
|
||||
}
|
||||
|
||||
private byte[] stopTracingImpl() {
|
||||
JsonObject json = sendMessage("stopTracing").getAsJsonObject();
|
||||
ArtifactImpl artifact = connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("artifact").get("guid").getAsString());
|
||||
byte[] data = artifact.readAllBytes();
|
||||
@@ -237,46 +295,18 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
|
||||
@Override
|
||||
void handleEvent(String event, JsonObject parameters) {
|
||||
switch (event) {
|
||||
case "context":
|
||||
didCreateContext(connection.getExistingObject(parameters.getAsJsonObject("context").get("guid").getAsString()));
|
||||
break;
|
||||
case "close":
|
||||
didClose();
|
||||
break;
|
||||
if ("close".equals(event)) {
|
||||
didClose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CDPSession newBrowserCDPSession() {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonObject result = sendMessage("newBrowserCDPSession", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = sendMessage("newBrowserCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
protected void connectToBrowserType(BrowserTypeImpl browserType, Path tracesDir){
|
||||
// Note: when using connect(), `browserType` is different from `this.parent`.
|
||||
// This is why browser type is not wired up in the constructor, and instead this separate method is called later on.
|
||||
this.browserType = browserType;
|
||||
this.tracePath = tracesDir;
|
||||
|
||||
for (BrowserContextImpl context : contexts) {
|
||||
context.tracing().setTracesDir(tracesDir);
|
||||
browserType.playwright.selectors.contextsForSelectors.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void didCreateContext(BrowserContextImpl context) {
|
||||
context.browser = this;
|
||||
contexts.add(context);
|
||||
// Note: when connecting to a browser, initial contexts arrive before `_browserType` is set,
|
||||
// and will be configured later in `ConnectToBrowserType`.
|
||||
if (browserType != null) {
|
||||
context.tracing().setTracesDir(tracePath);
|
||||
browserType.playwright.selectors.contextsForSelectors.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void didClose() {
|
||||
isConnected = false;
|
||||
listeners.notify(EventType.DISCONNECTED, this);
|
||||
|
||||
@@ -22,30 +22,34 @@ import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Browser;
|
||||
import com.microsoft.playwright.BrowserType;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
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 {
|
||||
protected PlaywrightImpl playwright;
|
||||
|
||||
BrowserTypeImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrowserImpl launch(LaunchOptions options) {
|
||||
return withLogging("BrowserType.launch", () -> launchImpl(options));
|
||||
}
|
||||
|
||||
private BrowserImpl launchImpl(LaunchOptions options) {
|
||||
if (options == null) {
|
||||
options = new LaunchOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonElement result = sendMessage("launch", params, TimeoutSettings.launchTimeout(options.timeout));
|
||||
JsonElement result = sendMessage("launch", params);
|
||||
BrowserImpl browser = connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.browserType = this;
|
||||
browser.launchOptions = options;
|
||||
@@ -54,6 +58,10 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
|
||||
@Override
|
||||
public Browser connect(String wsEndpoint, ConnectOptions options) {
|
||||
return withLogging("BrowserType.connect", () -> connectImpl(wsEndpoint, options));
|
||||
}
|
||||
|
||||
private Browser connectImpl(String wsEndpoint, ConnectOptions options) {
|
||||
if (options == null) {
|
||||
options = new ConnectOptions();
|
||||
}
|
||||
@@ -76,12 +84,7 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
headers.addProperty("x-playwright-browser", name());
|
||||
}
|
||||
|
||||
Double timeout = options.timeout;
|
||||
if (timeout == null) {
|
||||
timeout = 0.0;
|
||||
}
|
||||
|
||||
JsonObject json = connection.localUtils().sendMessage("connect", params, timeout).getAsJsonObject();
|
||||
JsonObject json = connection.localUtils().sendMessage("connect", params).getAsJsonObject();
|
||||
JsonPipe pipe = connection.getExistingObject(json.getAsJsonObject("pipe").get("guid").getAsString());
|
||||
Connection connection = new Connection(pipe, this.connection.env, this.connection.localUtils);
|
||||
PlaywrightImpl playwright = connection.initializePlaywright();
|
||||
@@ -93,13 +96,14 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
}
|
||||
throw new PlaywrightException("Malformed endpoint. Did you use launchServer method?");
|
||||
}
|
||||
playwright.selectors = this.playwright.selectors;
|
||||
playwright.initSharedSelectors(this.connection.getExistingObject("Playwright"));
|
||||
BrowserImpl browser = connection.getExistingObject(playwright.initializer.getAsJsonObject("preLaunchedBrowser").get("guid").getAsString());
|
||||
browser.isConnectedOverWebSocket = true;
|
||||
browser.connectToBrowserType(this, null);
|
||||
browser.browserType = this;
|
||||
Consumer<JsonPipe> connectionCloseListener = t -> browser.notifyRemoteClosed();
|
||||
pipe.onClose(connectionCloseListener);
|
||||
browser.onDisconnected(b -> {
|
||||
playwright.unregisterSelectors();
|
||||
pipe.offClose(connectionCloseListener);
|
||||
try {
|
||||
connection.close();
|
||||
@@ -115,16 +119,25 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
if (!"chromium".equals(name())) {
|
||||
throw new PlaywrightException("Connecting over CDP is only supported in Chromium.");
|
||||
}
|
||||
return withLogging("BrowserType.connectOverCDP", () -> connectOverCDPImpl(endpointURL, options));
|
||||
}
|
||||
|
||||
private Browser connectOverCDPImpl(String endpointURL, ConnectOverCDPOptions options) {
|
||||
if (options == null) {
|
||||
options = new ConnectOverCDPOptions();
|
||||
}
|
||||
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("endpointURL", endpointURL);
|
||||
JsonObject json = sendMessage("connectOverCDP", params, TimeoutSettings.launchTimeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("connectOverCDP", params).getAsJsonObject();
|
||||
|
||||
BrowserImpl browser = connection.getExistingObject(json.getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.connectToBrowserType(this, null);
|
||||
browser.browserType = this;
|
||||
if (json.has("defaultContext")) {
|
||||
String contextId = json.getAsJsonObject("defaultContext").get("guid").getAsString();
|
||||
BrowserContextImpl defaultContext = connection.getExistingObject(contextId);
|
||||
browser.contexts.add(defaultContext);
|
||||
}
|
||||
return browser;
|
||||
}
|
||||
|
||||
@@ -134,19 +147,54 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
|
||||
@Override
|
||||
public BrowserContextImpl launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options) {
|
||||
return withLogging("BrowserType.launchPersistentContext",
|
||||
() -> launchPersistentContextImpl(userDataDir, options));
|
||||
}
|
||||
|
||||
private BrowserContextImpl launchPersistentContextImpl(Path userDataDir, LaunchPersistentContextOptions options) {
|
||||
if (options == null) {
|
||||
options = new LaunchPersistentContextOptions();
|
||||
} else {
|
||||
// Make a copy so that we can nullify some fields below.
|
||||
options = convertType(options, LaunchPersistentContextOptions.class);
|
||||
}
|
||||
|
||||
Browser.NewContextOptions harOptions = convertType(options, Browser.NewContextOptions.class);
|
||||
options.recordHarContent = null;
|
||||
options.recordHarMode = null;
|
||||
options.recordHarPath = null;
|
||||
options.recordHarOmitContent = null;
|
||||
options.recordHarUrlFilter = null;
|
||||
JsonObject recordHar = null;
|
||||
Path recordHarPath = options.recordHarPath;
|
||||
HarContentPolicy harContentPolicy = null;
|
||||
if (options.recordHarPath != null) {
|
||||
recordHar = new JsonObject();
|
||||
recordHar.addProperty("path", options.recordHarPath.toString());
|
||||
if (options.recordHarContent != null) {
|
||||
harContentPolicy = options.recordHarContent;
|
||||
} else if (options.recordHarOmitContent != null && options.recordHarOmitContent) {
|
||||
harContentPolicy = HarContentPolicy.OMIT;
|
||||
}
|
||||
if (harContentPolicy != null) {
|
||||
recordHar.addProperty("content", harContentPolicy.name().toLowerCase());
|
||||
}
|
||||
if (options.recordHarMode != null) {
|
||||
recordHar.addProperty("mode", options.recordHarMode.toString().toLowerCase());
|
||||
}
|
||||
addHarUrlFilter(recordHar, options.recordHarUrlFilter);
|
||||
options.recordHarPath = null;
|
||||
options.recordHarMode = null;
|
||||
options.recordHarOmitContent = null;
|
||||
options.recordHarContent = null;
|
||||
options.recordHarUrlFilter = null;
|
||||
} else {
|
||||
if (options.recordHarOmitContent != null) {
|
||||
throw new PlaywrightException("recordHarOmitContent is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarUrlFilter != null) {
|
||||
throw new PlaywrightException("recordHarUrlFilter is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarMode != null) {
|
||||
throw new PlaywrightException("recordHarMode is set but recordHarPath is null");
|
||||
}
|
||||
if (options.recordHarContent != null) {
|
||||
throw new PlaywrightException("recordHarContent is set but recordHarPath is null");
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (!userDataDir.isAbsolute() && !userDataDir.toString().isEmpty()) {
|
||||
@@ -154,6 +202,9 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
userDataDir = cwd.resolve(userDataDir);
|
||||
}
|
||||
params.addProperty("userDataDir", userDataDir.toString());
|
||||
if (recordHar != null) {
|
||||
params.add("recordHar", recordHar);
|
||||
}
|
||||
if (options.recordVideoDir != null) {
|
||||
JsonObject recordVideo = new JsonObject();
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toAbsolutePath().toString());
|
||||
@@ -181,13 +232,13 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
}
|
||||
params.add("selectorEngines", gson().toJsonTree(playwright.selectors.selectorEngines));
|
||||
params.addProperty("testIdAttributeName", playwright.selectors.testIdAttributeName);
|
||||
JsonObject json = sendMessage("launchPersistentContext", params, TimeoutSettings.launchTimeout(options.timeout)).getAsJsonObject();
|
||||
BrowserImpl browser = connection.getExistingObject(json.getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.connectToBrowserType(this, options.tracesDir);
|
||||
JsonObject json = sendMessage("launchPersistentContext", params).getAsJsonObject();
|
||||
BrowserContextImpl context = connection.getExistingObject(json.getAsJsonObject("context").get("guid").getAsString());
|
||||
context.initializeHarFromOptions(harOptions);
|
||||
context.videosDir = options.recordVideoDir;
|
||||
if (options.baseURL != null) {
|
||||
context.setBaseUrl(options.baseURL);
|
||||
}
|
||||
context.setRecordHar(recordHarPath, harContentPolicy);
|
||||
context.tracing().setTracesDir(options.tracesDir);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ class ChannelOwner extends LoggingSupport {
|
||||
final String guid;
|
||||
final JsonObject initializer;
|
||||
private boolean wasCollected;
|
||||
|
||||
static Double NO_TIMEOUT = null;
|
||||
private boolean isInternalType;
|
||||
|
||||
protected ChannelOwner(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
this(parent.connection, parent, type, guid, initializer);
|
||||
@@ -60,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,20 +87,16 @@ class ChannelOwner extends LoggingSupport {
|
||||
return new WaitForEventLogger<>(this, apiName, code).get();
|
||||
}
|
||||
|
||||
|
||||
void withTitle(String title, Runnable code) {
|
||||
withTitle(title, () -> {
|
||||
code.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
<T> T withTitle(String title, Supplier<T> code) {
|
||||
String previousTitle = connection.setTitle(title);
|
||||
@Override
|
||||
<T> T withLogging(String apiName, Supplier<T> code) {
|
||||
if (isInternalType) {
|
||||
apiName = null;
|
||||
}
|
||||
String previousApiName = connection.setApiName(apiName);
|
||||
try {
|
||||
return code.get();
|
||||
return super.withLogging(apiName, code);
|
||||
} finally {
|
||||
connection.setTitle(previousTitle);
|
||||
connection.setApiName(previousApiName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,16 +110,11 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
|
||||
JsonElement sendMessage(String method) {
|
||||
return sendMessage(method, new JsonObject(), NO_TIMEOUT);
|
||||
return sendMessage(method, new JsonObject());
|
||||
}
|
||||
|
||||
JsonElement sendMessage(String method, JsonObject params, Double timeout) {
|
||||
JsonElement sendMessage(String method, JsonObject params) {
|
||||
checkNotCollected();
|
||||
if (timeout != null) {
|
||||
params.addProperty("timeout", timeout);
|
||||
} else if (params.has("timeout")) {
|
||||
throw new PlaywrightException("Internal error: timeout must be passed explicitly.");
|
||||
}
|
||||
return connection.sendMessage(guid, method, params);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import com.microsoft.playwright.Clock;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
|
||||
class ClockImpl implements Clock {
|
||||
private final ChannelOwner browserContext;
|
||||
|
||||
@@ -16,7 +14,8 @@ class ClockImpl implements Clock {
|
||||
|
||||
private void sendMessageWithLogging(String method, JsonObject params) {
|
||||
String capitalizedMethod = method.substring(0, 1).toUpperCase() + method.substring(1);
|
||||
browserContext.sendMessage("clock" + capitalizedMethod, params, NO_TIMEOUT);
|
||||
browserContext.withLogging("Clock." + method,
|
||||
() -> browserContext.sendMessage("clock" + capitalizedMethod, params));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.TimeoutError;
|
||||
|
||||
@@ -63,8 +64,7 @@ public class Connection {
|
||||
private int lastId = 0;
|
||||
private final StackTraceCollector stackTraceCollector;
|
||||
private final Map<Integer, WaitableResult<JsonElement>> callbacks = new HashMap<>();
|
||||
private String title;
|
||||
private boolean titleReported = false;
|
||||
private String apiName;
|
||||
private static final boolean isLogging;
|
||||
static {
|
||||
String debug = System.getenv("DEBUG");
|
||||
@@ -83,7 +83,7 @@ public class Connection {
|
||||
PlaywrightImpl initialize() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("sdkLanguage", "java");
|
||||
JsonElement result = sendMessage("initialize", params.getAsJsonObject(), NO_TIMEOUT);
|
||||
JsonElement result = sendMessage("initialize", params.getAsJsonObject());
|
||||
return this.connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("playwright").get("guid").getAsString());
|
||||
}
|
||||
}
|
||||
@@ -116,10 +116,9 @@ public class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
String setTitle(String newTitle) {
|
||||
String previous = title;
|
||||
titleReported = false;
|
||||
title = newTitle;
|
||||
String setApiName(String name) {
|
||||
String previous = apiName;
|
||||
apiName = name;
|
||||
return previous;
|
||||
}
|
||||
|
||||
@@ -147,14 +146,12 @@ public class Connection {
|
||||
JsonObject metadata = new JsonObject();
|
||||
metadata.addProperty("wallTime", currentTimeMillis());
|
||||
JsonArray stack = null;
|
||||
if (titleReported) {
|
||||
if (apiName == null) {
|
||||
metadata.addProperty("internal", true);
|
||||
} else {
|
||||
if (title != null) {
|
||||
metadata.addProperty("title", title);
|
||||
// All but first message in a custom-titled API call are considered internal and will be hidden from the inspector.
|
||||
titleReported = true;
|
||||
}
|
||||
metadata.addProperty("apiName", apiName);
|
||||
// All but first message in an API call are considered internal and will be hidden from the inspector.
|
||||
apiName = null;
|
||||
if (stackTraceCollector != null) {
|
||||
stack = stackTraceCollector.currentStackTrace();
|
||||
if (!stack.isEmpty()) {
|
||||
@@ -376,6 +373,9 @@ public class Connection {
|
||||
case "Stream":
|
||||
result = new Stream(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Selectors":
|
||||
result = new SelectorsImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "SocksSupport":
|
||||
break;
|
||||
case "Tracing":
|
||||
|
||||
@@ -20,10 +20,13 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.ConsoleMessage;
|
||||
import com.microsoft.playwright.JSHandle;
|
||||
import com.microsoft.playwright.Page;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
public class ConsoleMessageImpl implements ConsoleMessage {
|
||||
private final Connection connection;
|
||||
private PageImpl page;
|
||||
|
||||
@@ -34,16 +34,18 @@ class DialogImpl extends ChannelOwner implements Dialog {
|
||||
|
||||
@Override
|
||||
public void accept(String promptText) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (promptText != null) {
|
||||
params.addProperty("promptText", promptText);
|
||||
}
|
||||
sendMessage("accept", params, NO_TIMEOUT);
|
||||
withLogging("Dialog.accept", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
if (promptText != null) {
|
||||
params.addProperty("promptText", promptText);
|
||||
}
|
||||
sendMessage("accept", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
sendMessage("dismiss");
|
||||
withLogging("Dialog.dismiss", () -> sendMessage("dismiss"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,22 +46,22 @@ class DownloadImpl implements Download {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
artifact.cancel();
|
||||
page.withLogging("Download.cancel", () -> artifact.cancel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream createReadStream() {
|
||||
return artifact.createReadStream();
|
||||
return page.withLogging("Download.createReadStream", () -> artifact.createReadStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
artifact.delete();
|
||||
page.withLogging("Download.delete", () -> artifact.delete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String failure() {
|
||||
return artifact.failure();
|
||||
return page.withLogging("Download.failure", () -> artifact.failure());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,11 +71,11 @@ class DownloadImpl implements Download {
|
||||
|
||||
@Override
|
||||
public Path path() {
|
||||
return artifact.pathAfterFinished();
|
||||
return page.withLogging("Download.path", () -> artifact.pathAfterFinished());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Path path) {
|
||||
artifact.saveAs(path);
|
||||
page.withLogging("Download.saveAs", () -> artifact.saveAs(path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,11 +40,8 @@ import static com.microsoft.playwright.options.ScreenshotType.JPEG;
|
||||
import static com.microsoft.playwright.options.ScreenshotType.PNG;
|
||||
|
||||
public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
private final FrameImpl frame;
|
||||
|
||||
ElementHandleImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this.frame = (FrameImpl)parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,83 +51,105 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public ElementHandle querySelector(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelector", params, NO_TIMEOUT);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("element");
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(element.get("guid").getAsString());
|
||||
return withLogging("ElementHandle.querySelector", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelector", params);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("element");
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(element.get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementHandle> querySelectorAll(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelectorAll", params, NO_TIMEOUT);
|
||||
JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements");
|
||||
if (elements == null) {
|
||||
return null;
|
||||
}
|
||||
List<ElementHandle> handles = new ArrayList<>();
|
||||
for (JsonElement item : elements) {
|
||||
handles.add(connection.getExistingObject(item.getAsJsonObject().get("guid").getAsString()));
|
||||
}
|
||||
return handles;
|
||||
return withLogging("ElementHandle.<", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelectorAll", params);
|
||||
JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements");
|
||||
if (elements == null) {
|
||||
return null;
|
||||
}
|
||||
List<ElementHandle> handles = new ArrayList<>();
|
||||
for (JsonElement item : elements) {
|
||||
handles.add(connection.getExistingObject(item.getAsJsonObject().get("guid").getAsString()));
|
||||
}
|
||||
return handles;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evalOnSelector(String selector, String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelector", params, NO_TIMEOUT);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return withLogging("ElementHandle.evalOnSelector", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelector", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evalOnSelectorAll(String selector, String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelectorAll", params, NO_TIMEOUT);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return withLogging("ElementHandle.evalOnSelectorAll", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelectorAll", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox boundingBox() {
|
||||
JsonObject json = sendMessage("boundingBox").getAsJsonObject();
|
||||
if (!json.has("value")) {
|
||||
return null;
|
||||
}
|
||||
return gson().fromJson(json.get("value"), BoundingBox.class);
|
||||
return withLogging("ElementHandle.boundingBox", () -> {
|
||||
JsonObject json = sendMessage("boundingBox").getAsJsonObject();
|
||||
if (!json.has("value")) {
|
||||
return null;
|
||||
}
|
||||
return gson().fromJson(json.get("value"), BoundingBox.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(CheckOptions options) {
|
||||
withLogging("ElementHandle.check", () -> checkImpl(options));
|
||||
}
|
||||
|
||||
private void checkImpl(CheckOptions options) {
|
||||
if (options == null) {
|
||||
options = new CheckOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("check", params, frame.timeout(options.timeout));
|
||||
sendMessage("check", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(ClickOptions options) {
|
||||
withLogging("ElementHandle.click", () -> clickImpl(options));
|
||||
}
|
||||
|
||||
private void clickImpl(ClickOptions options) {
|
||||
if (options == null) {
|
||||
options = new ClickOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("click", params, frame.timeout(options.timeout));
|
||||
sendMessage("click", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame contentFrame() {
|
||||
return withLogging("ElementHandle.contentFrame", () -> contentFrameImpl());
|
||||
}
|
||||
|
||||
private Frame contentFrameImpl() {
|
||||
JsonObject json = sendMessage("contentFrame").getAsJsonObject();
|
||||
if (!json.has("frame")) {
|
||||
return null;
|
||||
@@ -140,132 +159,177 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public void dblclick(DblclickOptions options) {
|
||||
withLogging("ElementHandle.dblclick", () -> dblclickImpl(options));
|
||||
}
|
||||
|
||||
private void dblclickImpl(DblclickOptions options) {
|
||||
if (options == null) {
|
||||
options = new DblclickOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("dblclick", params, frame.timeout(options.timeout));
|
||||
sendMessage("dblclick", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchEvent(String type, Object eventInit) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("type", type);
|
||||
params.add("eventInit", gson().toJsonTree(serializeArgument(eventInit)));
|
||||
sendMessage("dispatchEvent", params, NO_TIMEOUT);
|
||||
withLogging("ElementHandle.dispatchEvent", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("type", type);
|
||||
params.add("eventInit", gson().toJsonTree(serializeArgument(eventInit)));
|
||||
sendMessage("dispatchEvent", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(String value, FillOptions options) {
|
||||
withLogging("ElementHandle.fill", () -> fillImpl(value, options));
|
||||
}
|
||||
|
||||
private void fillImpl(String value, FillOptions options) {
|
||||
if (options == null) {
|
||||
options = new FillOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("value", value);
|
||||
sendMessage("fill", params, frame.timeout(options.timeout));
|
||||
sendMessage("fill", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focus() {
|
||||
sendMessage("focus");
|
||||
withLogging("ElementHandle.focus", () -> sendMessage("focus"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String name) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
JsonObject json = sendMessage("getAttribute", params, NO_TIMEOUT).getAsJsonObject();
|
||||
return json.has("value") ? json.get("value").getAsString() : null;
|
||||
return withLogging("ElementHandle.getAttribute", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
JsonObject json = sendMessage("getAttribute", params).getAsJsonObject();
|
||||
return json.has("value") ? json.get("value").getAsString() : null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hover(HoverOptions options) {
|
||||
withLogging("ElementHandle.hover", () -> hoverImpl(options));
|
||||
}
|
||||
|
||||
private void hoverImpl(HoverOptions options) {
|
||||
if (options == null) {
|
||||
options = new HoverOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("hover", params, frame.timeout(options.timeout));
|
||||
sendMessage("hover", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerHTML() {
|
||||
JsonObject json = sendMessage("innerHTML").getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
return withLogging("ElementHandle.innerHTML", () -> {
|
||||
JsonObject json = sendMessage("innerHTML").getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerText() {
|
||||
JsonObject json = sendMessage("innerText").getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
return withLogging("ElementHandle.innerText", () -> {
|
||||
JsonObject json = sendMessage("innerText").getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputValue(InputValueOptions options) {
|
||||
return withLogging("ElementHandle.inputValue", () -> inputValueImpl(options));
|
||||
}
|
||||
|
||||
private String inputValueImpl(InputValueOptions options) {
|
||||
if (options == null) {
|
||||
options = new InputValueOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonObject json = sendMessage("inputValue", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("inputValue", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
JsonObject json = sendMessage("isChecked").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isChecked", () -> {
|
||||
JsonObject json = sendMessage("isChecked").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisabled() {
|
||||
JsonObject json = sendMessage("isDisabled").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isDisabled", () -> {
|
||||
JsonObject json = sendMessage("isDisabled").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable() {
|
||||
JsonObject json = sendMessage("isEditable").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isEditable", () -> {
|
||||
JsonObject json = sendMessage("isEditable").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
JsonObject json = sendMessage("isEnabled").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isEnabled", () -> {
|
||||
JsonObject json = sendMessage("isEnabled").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
JsonObject json = sendMessage("isHidden").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isHidden", () -> {
|
||||
JsonObject json = sendMessage("isHidden").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
JsonObject json = sendMessage("isVisible").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
return withLogging("ElementHandle.isVisible", () -> {
|
||||
JsonObject json = sendMessage("isVisible").getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameImpl ownerFrame() {
|
||||
JsonObject json = sendMessage("ownerFrame").getAsJsonObject();
|
||||
if (!json.has("frame")) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(json.getAsJsonObject("frame").get("guid").getAsString());
|
||||
return withLogging("ElementHandle.ownerFrame", () -> {
|
||||
JsonObject json = sendMessage("ownerFrame").getAsJsonObject();
|
||||
if (!json.has("frame")) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(json.getAsJsonObject("frame").get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void press(String key, PressOptions options) {
|
||||
withLogging("ElementHandle.press", () -> pressImpl(key, options));
|
||||
}
|
||||
private void pressImpl(String key, PressOptions options) {
|
||||
if (options == null) {
|
||||
options = new PressOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("key", key);
|
||||
sendMessage("press", params, frame.timeout(options.timeout));
|
||||
sendMessage("press", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] screenshot(ScreenshotOptions options) {
|
||||
return withLogging("ElementHandle.screenshot", () -> screenshotImpl(options));
|
||||
}
|
||||
|
||||
private byte[] screenshotImpl(ScreenshotOptions options) {
|
||||
if (options == null) {
|
||||
options = new ScreenshotOptions();
|
||||
}
|
||||
@@ -284,7 +348,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.remove("path");
|
||||
JsonObject json = sendMessage("screenshot", params, frame.timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("screenshot", params).getAsJsonObject();
|
||||
|
||||
byte[] buffer = Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
if (options.path != null) {
|
||||
@@ -295,11 +359,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public void scrollIntoViewIfNeeded(ScrollIntoViewIfNeededOptions options) {
|
||||
if (options == null) {
|
||||
options = new ScrollIntoViewIfNeededOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("scrollIntoViewIfNeeded", params, frame.timeout(options.timeout));
|
||||
withLogging("ElementHandle.scrollIntoViewIfNeeded", () -> scrollIntoViewIfNeededImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -323,7 +383,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
if (values != null) {
|
||||
params.add("options", toSelectValueOrLabel(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -332,6 +392,13 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
return selectOption(values, options);
|
||||
}
|
||||
|
||||
private void scrollIntoViewIfNeededImpl(ScrollIntoViewIfNeededOptions options) {
|
||||
if (options == null) {
|
||||
options = new ScrollIntoViewIfNeededOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("scrollIntoViewIfNeeded", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(SelectOption[] values, SelectOptionOptions options) {
|
||||
@@ -342,7 +409,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
if (values != null) {
|
||||
params.add("options", gson().toJsonTree(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -354,21 +421,19 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
if (values != null) {
|
||||
params.add("elements", Serialization.toProtocol(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
private List<String> selectOption(JsonObject params, Double timeout) {
|
||||
JsonObject json = sendMessage("selectOption", params, frame.timeout(timeout)).getAsJsonObject();
|
||||
return parseStringList(json.getAsJsonArray("values"));
|
||||
private List<String> selectOption(JsonObject params) {
|
||||
return withLogging("SelectOption", () -> {
|
||||
JsonObject json = sendMessage("selectOption", params).getAsJsonObject();
|
||||
return parseStringList(json.getAsJsonArray("values"));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectText(SelectTextOptions options) {
|
||||
if (options == null) {
|
||||
options = new SelectTextOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("selectText", params, frame.timeout(options.timeout));
|
||||
withLogging("ElementHandle.selectText", () -> selectTextImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -385,9 +450,20 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
setInputFiles(new Path[]{files}, options);
|
||||
}
|
||||
|
||||
private void selectTextImpl(SelectTextOptions options) {
|
||||
if (options == null) {
|
||||
options = new SelectTextOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("selectText", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputFiles(Path[] files, SetInputFilesOptions options) {
|
||||
withLogging("ElementHandle.setInputFiles", () -> setInputFilesImpl(files, options));
|
||||
}
|
||||
|
||||
void setInputFilesImpl(Path[] files, SetInputFilesOptions options) {
|
||||
FrameImpl frame = ownerFrame();
|
||||
if (frame == null) {
|
||||
throw new Error("Cannot set input files to detached element");
|
||||
@@ -397,7 +473,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addFilePathUploadParams(files, params, frame.page().context());
|
||||
sendMessage("setInputFiles", params, frame.timeout(options.timeout));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -407,51 +483,77 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public void setInputFiles(FilePayload[] files, SetInputFilesOptions options) {
|
||||
withLogging("ElementHandle.setInputFiles", () -> setInputFilesImpl(files, options));
|
||||
}
|
||||
|
||||
void setInputFilesImpl(FilePayload[] files, SetInputFilesOptions options) {
|
||||
checkFilePayloadSize(files);
|
||||
if (options == null) {
|
||||
options = new SetInputFilesOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.add("payloads", Serialization.toJsonArray(files));
|
||||
sendMessage("setInputFiles", params, frame.timeout(options.timeout));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tap(TapOptions options) {
|
||||
withLogging("ElementHandle.tap", () -> tapImpl(options));
|
||||
}
|
||||
|
||||
private void tapImpl(TapOptions options) {
|
||||
if (options == null) {
|
||||
options = new TapOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("tap", params, frame.timeout(options.timeout));
|
||||
sendMessage("tap", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String textContent() {
|
||||
JsonObject json = sendMessage("textContent").getAsJsonObject();
|
||||
return json.has("value") ? json.get("value").getAsString() : null;
|
||||
return withLogging("ElementHandle.textContent", () -> textContentImpl());
|
||||
}
|
||||
|
||||
private String textContentImpl() {
|
||||
return withLogging("ElementHandle.textContent", () -> {
|
||||
JsonObject json = sendMessage("textContent").getAsJsonObject();
|
||||
return json.has("value") ? json.get("value").getAsString() : null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void type(String text, TypeOptions options) {
|
||||
withLogging("ElementHandle.type", () -> typeImpl(text, options));
|
||||
}
|
||||
|
||||
private void typeImpl(String text, TypeOptions options) {
|
||||
if (options == null) {
|
||||
options = new TypeOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("text", text);
|
||||
sendMessage("type", params, frame.timeout(options.timeout));
|
||||
sendMessage("type", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncheck(UncheckOptions options) {
|
||||
withLogging("ElementHandle.uncheck", () -> uncheckImpl(options));
|
||||
}
|
||||
|
||||
private void uncheckImpl(UncheckOptions options) {
|
||||
if (options == null) {
|
||||
options = new UncheckOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("uncheck", params, frame.timeout(options.timeout));
|
||||
sendMessage("uncheck", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForElementState(ElementState state, WaitForElementStateOptions options) {
|
||||
withLogging("ElementHandle.waitForElementState", () -> waitForElementStateImpl(state, options));
|
||||
}
|
||||
|
||||
private void waitForElementStateImpl(ElementState state, WaitForElementStateOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForElementStateOptions();
|
||||
}
|
||||
@@ -460,7 +562,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("state", toProtocol(state));
|
||||
sendMessage("waitForElementState", params, frame.timeout(options.timeout));
|
||||
sendMessage("waitForElementState", params);
|
||||
}
|
||||
|
||||
private static String toProtocol(ElementState state) {
|
||||
@@ -469,12 +571,16 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public ElementHandle waitForSelector(String selector, WaitForSelectorOptions options) {
|
||||
return withLogging("ElementHandle.waitForSelector", () -> waitForSelectorImpl(selector, options));
|
||||
}
|
||||
|
||||
private ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForSelectorOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("waitForSelector", params, frame.timeout(options.timeout)).getAsJsonObject();
|
||||
JsonElement json = sendMessage("waitForSelector", params);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("element");
|
||||
if (element == null) {
|
||||
return null;
|
||||
|
||||
@@ -58,7 +58,8 @@ class FileChooserImpl implements FileChooser {
|
||||
|
||||
@Override
|
||||
public void setFiles(Path[] files, SetFilesOptions options) {
|
||||
element.setInputFiles(files, convertType(options, ElementHandle.SetInputFilesOptions.class));
|
||||
page.withLogging("FileChooser.setInputFiles",
|
||||
() -> element.setInputFilesImpl(files, convertType(options, ElementHandle.SetInputFilesOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,6 +69,7 @@ class FileChooserImpl implements FileChooser {
|
||||
|
||||
@Override
|
||||
public void setFiles(FilePayload[] files, SetFilesOptions options) {
|
||||
element.setInputFiles(files, convertType(options, ElementHandle.SetInputFilesOptions.class));
|
||||
page.withLogging("FileChooser.setInputFiles",
|
||||
() -> element.setInputFilesImpl(files, convertType(options, ElementHandle.SetInputFilesOptions.class)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,16 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public ElementHandle querySelector(String selector, QuerySelectorOptions options) {
|
||||
return withLogging("Frame.querySelector", () -> querySelectorImpl(selector, options));
|
||||
}
|
||||
|
||||
ElementHandleImpl querySelectorImpl(String selector, QuerySelectorOptions options) {
|
||||
if (options == null) {
|
||||
options = new QuerySelectorOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelector", params, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("querySelector", params);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("element");
|
||||
if (element == null) {
|
||||
return null;
|
||||
@@ -89,18 +93,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public List<ElementHandle> querySelectorAll(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelectorAll", params, NO_TIMEOUT);
|
||||
JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements");
|
||||
if (elements == null) {
|
||||
return null;
|
||||
}
|
||||
List<ElementHandle> handles = new ArrayList<>();
|
||||
for (JsonElement item : elements) {
|
||||
handles.add(connection.getExistingObject(item.getAsJsonObject().get("guid").getAsString()));
|
||||
}
|
||||
return handles;
|
||||
return withLogging("Frame.querySelectorAll", () -> querySelectorAllImpl(selector));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,7 +110,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
|
||||
return selectOptionImpl(selector, values, options);
|
||||
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,10 +119,24 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
return selectOption(selector, values, options);
|
||||
}
|
||||
|
||||
List<ElementHandle> querySelectorAllImpl(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonElement json = sendMessage("querySelectorAll", params);
|
||||
JsonArray elements = json.getAsJsonObject().getAsJsonArray("elements");
|
||||
if (elements == null) {
|
||||
return null;
|
||||
}
|
||||
List<ElementHandle> handles = new ArrayList<>();
|
||||
for (JsonElement item : elements) {
|
||||
handles.add(connection.getExistingObject(item.getAsJsonObject().get("guid").getAsString()));
|
||||
}
|
||||
return handles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evalOnSelector(String selector, String pageFunction, Object arg, EvalOnSelectorOptions options) {
|
||||
return evalOnSelectorImpl(selector, pageFunction, arg, options);
|
||||
return withLogging("Frame.evalOnSelector", () -> evalOnSelectorImpl(selector, pageFunction, arg, options));
|
||||
}
|
||||
|
||||
Object evalOnSelectorImpl(String selector, String pageFunction, Object arg, EvalOnSelectorOptions options) {
|
||||
@@ -140,14 +147,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelector", params, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("evalOnSelector", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evalOnSelectorAll(String selector, String pageFunction, Object arg) {
|
||||
return evalOnSelectorAllImpl(selector, pageFunction, arg);
|
||||
return withLogging("Frame.evalOnSelectorAll", () -> evalOnSelectorAllImpl(selector, pageFunction, arg));
|
||||
}
|
||||
|
||||
Object evalOnSelectorAllImpl(String selector, String pageFunction, Object arg) {
|
||||
@@ -155,14 +162,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evalOnSelectorAll", params, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("evalOnSelectorAll", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandle addScriptTag(AddScriptTagOptions options){
|
||||
return addScriptTagImpl(options);
|
||||
return withLogging("Frame.addScriptTag", () -> addScriptTagImpl(options));
|
||||
}
|
||||
|
||||
ElementHandle addScriptTagImpl(AddScriptTagOptions options) {
|
||||
@@ -182,13 +189,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
content = addSourceUrlToScript(content, options.path);
|
||||
jsonOptions.addProperty("content", content);
|
||||
}
|
||||
JsonElement json = sendMessage("addScriptTag", jsonOptions, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("addScriptTag", jsonOptions);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("element").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandle addStyleTag(AddStyleTagOptions options){
|
||||
return addStyleTagImpl(options);
|
||||
return withLogging("Frame.addStyleTag", () -> addStyleTagImpl(options));
|
||||
}
|
||||
|
||||
ElementHandle addStyleTagImpl(AddStyleTagOptions options) {
|
||||
@@ -208,18 +215,22 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
content += "/*# sourceURL=" + options.path.toString().replace("\n", "") + "*/";
|
||||
jsonOptions.addProperty("content", content);
|
||||
}
|
||||
JsonElement json = sendMessage("addStyleTag", jsonOptions, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("addStyleTag", jsonOptions);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("element").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(String selector, CheckOptions options){
|
||||
withLogging("Frame.check", () -> checkImpl(selector, options));
|
||||
}
|
||||
|
||||
void checkImpl(String selector, CheckOptions options) {
|
||||
if (options == null) {
|
||||
options = new CheckOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("check", params, timeout(options.timeout));
|
||||
sendMessage("check", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,7 +240,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void click(String selector, ClickOptions options) {
|
||||
clickImpl(selector, options);
|
||||
withLogging("Frame.click", () -> clickImpl(selector, options));
|
||||
}
|
||||
|
||||
void clickImpl(String selector, ClickOptions options) {
|
||||
@@ -238,26 +249,38 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("click", params, timeout(options.timeout));
|
||||
sendMessage("click", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String content() {
|
||||
return withLogging("Frame.content", () -> contentImpl());
|
||||
}
|
||||
|
||||
String contentImpl() {
|
||||
return sendMessage("content").getAsJsonObject().get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dblclick(String selector, DblclickOptions options) {
|
||||
withLogging("Frame.dblclick", () -> dblclickImpl(selector, options));
|
||||
}
|
||||
|
||||
void dblclickImpl(String selector, DblclickOptions options) {
|
||||
if (options == null) {
|
||||
options = new DblclickOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("dblclick", params, timeout(options.timeout));
|
||||
sendMessage("dblclick", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options) {
|
||||
withLogging("Frame.dispatchEvent", () -> dispatchEventImpl(selector, type, eventInit, options));
|
||||
}
|
||||
|
||||
void dispatchEventImpl(String selector, String type, Object eventInit, DispatchEventOptions options) {
|
||||
if (options == null) {
|
||||
options = new DispatchEventOptions();
|
||||
}
|
||||
@@ -265,55 +288,71 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("type", type);
|
||||
params.add("eventInit", gson().toJsonTree(serializeArgument(eventInit)));
|
||||
sendMessage("dispatchEvent", params, timeout(options.timeout));
|
||||
sendMessage("dispatchEvent", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(String expression, Object arg) {
|
||||
return withLogging("Frame.evaluate", () -> evaluateImpl(expression, arg));
|
||||
}
|
||||
|
||||
Object evaluateImpl(String expression, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", expression);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpression", params, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("evaluateExpression", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle evaluateHandle(String pageFunction, Object arg) {
|
||||
return withLogging("Frame.evaluateHandle", () -> evaluateHandleImpl(pageFunction, arg));
|
||||
}
|
||||
|
||||
JSHandle evaluateHandleImpl(String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params, NO_TIMEOUT);
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(String selector, String value, FillOptions options) {
|
||||
withLogging("Frame.fill", () -> fillImpl(selector, value, options));
|
||||
}
|
||||
|
||||
void fillImpl(String selector, String value, FillOptions options) {
|
||||
if (options == null) {
|
||||
options = new FillOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("value", value);
|
||||
sendMessage("fill", params, timeout(options.timeout));
|
||||
sendMessage("fill", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focus(String selector, FocusOptions options) {
|
||||
withLogging("Frame.focus", () -> focusImpl(selector, options));
|
||||
}
|
||||
|
||||
void focusImpl(String selector, FocusOptions options) {
|
||||
if (options == null) {
|
||||
options = new FocusOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("focus", params, timeout(options.timeout));
|
||||
sendMessage("focus", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandle frameElement() {
|
||||
JsonObject json = sendMessage("frameElement").getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("element").get("guid").getAsString());
|
||||
return withLogging("Frame.frameElement", () -> frameElementImpl());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -321,9 +360,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
return new FrameLocatorImpl(this, selector);
|
||||
}
|
||||
|
||||
ElementHandle frameElementImpl() {
|
||||
JsonObject json = sendMessage("frameElement").getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("element").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttribute(String selector, String name, GetAttributeOptions options) {
|
||||
return getAttributeImpl(selector, name, options);
|
||||
return withLogging("Frame.getAttribute", () -> getAttributeImpl(selector, name, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -398,7 +442,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("name", name);
|
||||
JsonObject json = sendMessage("getAttribute", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("getAttribute", params).getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
@@ -407,7 +451,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public ResponseImpl navigate(String url, NavigateOptions options) {
|
||||
return navigateImpl(url, options);
|
||||
return withLogging("Page.navigate", () -> navigateImpl(url, options));
|
||||
}
|
||||
|
||||
ResponseImpl navigateImpl(String url, NavigateOptions options) {
|
||||
@@ -416,7 +460,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("url", url);
|
||||
JsonElement result = sendMessage("goto", params, navigationTimeout(options.timeout));
|
||||
JsonElement result = sendMessage("goto", params);
|
||||
JsonObject jsonResponse = result.getAsJsonObject().getAsJsonObject("response");
|
||||
if (jsonResponse == null) {
|
||||
return null;
|
||||
@@ -426,7 +470,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void hover(String selector, HoverOptions options) {
|
||||
hoverImpl(selector, options);
|
||||
withLogging("Frame.hover", () -> hoverImpl(selector, options));
|
||||
}
|
||||
|
||||
void hoverImpl(String selector, HoverOptions options) {
|
||||
@@ -435,12 +479,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("hover", params, timeout(options.timeout));
|
||||
sendMessage("hover", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dragAndDrop(String source, String target, DragAndDropOptions options) {
|
||||
dragAndDropImpl(source, target, options);
|
||||
withLogging("Frame.dragAndDrop", () -> dragAndDropImpl(source, target, options));
|
||||
}
|
||||
|
||||
void dragAndDropImpl(String source, String target, DragAndDropOptions options) {
|
||||
@@ -450,12 +494,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("source", source);
|
||||
params.addProperty("target", target);
|
||||
sendMessage("dragAndDrop", params, timeout(options.timeout));
|
||||
sendMessage("dragAndDrop", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerHTML(String selector, InnerHTMLOptions options) {
|
||||
return innerHTMLImpl(selector, options);
|
||||
return withLogging("Frame.innerHTML", () -> innerHTMLImpl(selector, options));
|
||||
}
|
||||
|
||||
String innerHTMLImpl(String selector, InnerHTMLOptions options) {
|
||||
@@ -464,13 +508,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("innerHTML", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("innerHTML", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerText(String selector, InnerTextOptions options) {
|
||||
return innerTextImpl(selector, options);
|
||||
return withLogging("Frame.innerText", () -> innerTextImpl(selector, options));
|
||||
}
|
||||
|
||||
String innerTextImpl(String selector, InnerTextOptions options) {
|
||||
@@ -479,13 +523,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("innerText", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("innerText", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputValue(String selector, InputValueOptions options) {
|
||||
return inputValueImpl(selector, options);
|
||||
return withLogging("Frame.inputValue", () -> inputValueImpl(selector, options));
|
||||
}
|
||||
|
||||
String inputValueImpl(String selector, InputValueOptions options) {
|
||||
@@ -494,13 +538,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("inputValue", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("inputValue", params).getAsJsonObject();
|
||||
return json.get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked(String selector, IsCheckedOptions options) {
|
||||
return isCheckedImpl(selector, options);
|
||||
return withLogging("Page.isChecked", () -> isCheckedImpl(selector, options));
|
||||
}
|
||||
|
||||
boolean isCheckedImpl(String selector, IsCheckedOptions options) {
|
||||
@@ -509,7 +553,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isChecked", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isChecked", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@@ -520,7 +564,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public boolean isDisabled(String selector, IsDisabledOptions options) {
|
||||
return isDisabledImpl(selector, options);
|
||||
return withLogging("Page.isDisabled", () -> isDisabledImpl(selector, options));
|
||||
}
|
||||
|
||||
boolean isDisabledImpl(String selector, IsDisabledOptions options) {
|
||||
@@ -529,13 +573,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isDisabled", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isDisabled", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(String selector, IsEditableOptions options) {
|
||||
return isEditableImpl(selector, options);
|
||||
return withLogging("Page.isEditable", () -> isEditableImpl(selector, options));
|
||||
}
|
||||
|
||||
boolean isEditableImpl(String selector, IsEditableOptions options) {
|
||||
@@ -544,13 +588,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isEditable", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isEditable", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(String selector, IsEnabledOptions options) {
|
||||
return isEnabledImpl(selector, options);
|
||||
return withLogging("Page.isEnabled", () -> isEnabledImpl(selector, options));
|
||||
}
|
||||
|
||||
boolean isEnabledImpl(String selector, IsEnabledOptions options) {
|
||||
@@ -559,13 +603,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isEnabled", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isEnabled", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(String selector, IsHiddenOptions options) {
|
||||
return isHiddenImpl(selector, options);
|
||||
return withLogging("Page.isHidden", () -> isHiddenImpl(selector, options));
|
||||
}
|
||||
|
||||
boolean isHiddenImpl(String selector, IsHiddenOptions options) {
|
||||
@@ -574,13 +618,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isHidden", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isHidden", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(String selector, IsVisibleOptions options) {
|
||||
return isVisibleImpl(selector, options);
|
||||
return withLogging("Page.isVisible", () -> isVisibleImpl(selector, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -594,7 +638,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject json = sendMessage("isVisible", params, timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("isVisible", params).getAsJsonObject();
|
||||
return json.get("value").getAsBoolean();
|
||||
}
|
||||
|
||||
@@ -615,7 +659,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void press(String selector, String key, PressOptions options) {
|
||||
pressImpl(selector, key, options);
|
||||
withLogging("Frame.press", () -> pressImpl(selector, key, options));
|
||||
}
|
||||
|
||||
void pressImpl(String selector, String key, PressOptions options) {
|
||||
@@ -625,12 +669,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("key", key);
|
||||
sendMessage("press", params, timeout(options.timeout));
|
||||
sendMessage("press", params);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, SelectOption[] values, SelectOptionOptions options) {
|
||||
return selectOptionImpl(selector, values, options);
|
||||
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, options));
|
||||
}
|
||||
|
||||
List<String> selectOptionImpl(String selector, SelectOption[] values, SelectOptionOptions options) {
|
||||
@@ -642,7 +686,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
if (values != null) {
|
||||
params.add("options", gson().toJsonTree(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
List<String> selectOptionImpl(String selector, String[] values, SelectOptionOptions options) {
|
||||
@@ -654,12 +698,12 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
if (values != null) {
|
||||
params.add("options", toSelectValueOrLabel(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, ElementHandle[] values, SelectOptionOptions options) {
|
||||
return selectOptionImpl(selector, values, options);
|
||||
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, options));
|
||||
}
|
||||
|
||||
List<String> selectOptionImpl(String selector, ElementHandle[] values, SelectOptionOptions options) {
|
||||
@@ -671,35 +715,30 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
if (values != null) {
|
||||
params.add("elements", Serialization.toProtocol(values));
|
||||
}
|
||||
return selectOption(params, options.timeout);
|
||||
return selectOption(params);
|
||||
}
|
||||
|
||||
private List<String> selectOption(JsonObject params, Double timeout) {
|
||||
JsonObject json = sendMessage("selectOption", params, timeout(timeout)).getAsJsonObject();
|
||||
private List<String> selectOption(JsonObject params) {
|
||||
JsonObject json = sendMessage("selectOption", params).getAsJsonObject();
|
||||
return parseStringList(json.getAsJsonArray("values"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(String selector, boolean checked, SetCheckedOptions options) {
|
||||
setCheckedImpl(selector, checked, options);
|
||||
withLogging("Frame.setChecked", () -> setCheckedImpl(selector, checked, options));
|
||||
}
|
||||
|
||||
void setCheckedImpl(String selector, boolean checked, SetCheckedOptions options) {
|
||||
if (checked) {
|
||||
check(selector, convertType(options, CheckOptions.class));
|
||||
checkImpl(selector, convertType(options, CheckOptions.class));
|
||||
} else {
|
||||
uncheck(selector, convertType(options, UncheckOptions.class));
|
||||
uncheckImpl(selector, convertType(options, UncheckOptions.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContent(String html, SetContentOptions options) {
|
||||
if (options == null) {
|
||||
options = new SetContentOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("html", html);
|
||||
sendMessage("setContent", params, navigationTimeout(options.timeout));
|
||||
withLogging("Frame.setContent", () -> setContentImpl(html, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -707,9 +746,18 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
setInputFiles(selector, new Path[] {files}, options);
|
||||
}
|
||||
|
||||
void setContentImpl(String html, SetContentOptions options) {
|
||||
if (options == null) {
|
||||
options = new SetContentOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("html", html);
|
||||
sendMessage("setContent", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputFiles(String selector, Path[] files, SetInputFilesOptions options) {
|
||||
setInputFilesImpl(selector, files, options);
|
||||
withLogging("Frame.setInputFiles", () -> setInputFilesImpl(selector, files, options));
|
||||
}
|
||||
|
||||
void setInputFilesImpl(String selector, Path[] files, SetInputFilesOptions options) {
|
||||
@@ -719,7 +767,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addFilePathUploadParams(files, params, page.context());
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("setInputFiles", params, timeout(options.timeout));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -729,7 +777,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void setInputFiles(String selector, FilePayload[] files, SetInputFilesOptions options) {
|
||||
setInputFilesImpl(selector, files, options);
|
||||
withLogging("Frame.setInputFiles", () -> setInputFilesImpl(selector, files, options));
|
||||
}
|
||||
|
||||
void setInputFilesImpl(String selector, FilePayload[] files, SetInputFilesOptions options) {
|
||||
@@ -740,54 +788,73 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.add("payloads", toJsonArray(files));
|
||||
sendMessage("setInputFiles", params, timeout(options.timeout));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tap(String selector, TapOptions options) {
|
||||
withLogging("Frame.tap", () -> tapImpl(selector, options));
|
||||
}
|
||||
void tapImpl(String selector, TapOptions options) {
|
||||
if (options == null) {
|
||||
options = new TapOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("tap", params, timeout(options.timeout));
|
||||
sendMessage("tap", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String textContent(String selector, TextContentOptions options) {
|
||||
return withLogging("Frame.textContent", () -> textContentImpl(selector, options));
|
||||
}
|
||||
|
||||
String textContentImpl(String selector, TextContentOptions options) {
|
||||
if (options == null) {
|
||||
options = new TextContentOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
return sendMessage("textContent", params, timeout(options.timeout)).getAsJsonObject().get("value").getAsString();
|
||||
return sendMessage("textContent", params).getAsJsonObject().get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String title() {
|
||||
return withLogging("Frame.title", () -> titleImpl());
|
||||
}
|
||||
|
||||
String titleImpl() {
|
||||
JsonElement json = sendMessage("title");
|
||||
return json.getAsJsonObject().get("value").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void type(String selector, String text, TypeOptions options) {
|
||||
withLogging("Frame.type", () -> typeImpl(selector, text, options));
|
||||
}
|
||||
|
||||
void typeImpl(String selector, String text, TypeOptions options) {
|
||||
if (options == null) {
|
||||
options = new TypeOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("text", text);
|
||||
sendMessage("type", params, timeout(options.timeout));
|
||||
sendMessage("type", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncheck(String selector, UncheckOptions options) {
|
||||
withLogging("Frame.uncheck", () -> uncheckImpl(selector, options));
|
||||
}
|
||||
|
||||
void uncheckImpl(String selector, UncheckOptions options) {
|
||||
if (options == null) {
|
||||
options = new UncheckOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("uncheck", params, timeout(options.timeout));
|
||||
sendMessage("uncheck", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -797,13 +864,17 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public JSHandle waitForFunction(String pageFunction, Object arg, WaitForFunctionOptions options) {
|
||||
return withLogging("Frame.waitForFunction", () -> waitForFunctionImpl(pageFunction, arg, options));
|
||||
}
|
||||
|
||||
JSHandle waitForFunctionImpl(String pageFunction, Object arg, WaitForFunctionOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFunctionOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("waitForFunction", params, timeout(options.timeout));
|
||||
JsonElement json = sendMessage("waitForFunction", params);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("handle");
|
||||
return connection.getExistingObject(element.get("guid").getAsString());
|
||||
}
|
||||
@@ -960,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, this.connection.localUtils, false);
|
||||
matcher = UrlMatcher.forOneOf(page.context().baseUrl, options.url);
|
||||
}
|
||||
logger.log("waiting for navigation " + matcher);
|
||||
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil, logger));
|
||||
@@ -972,6 +1043,10 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public ElementHandle waitForSelector(String selector, WaitForSelectorOptions options) {
|
||||
return withLogging("Frame.waitForSelector", () -> waitForSelectorImpl(selector, options));
|
||||
}
|
||||
|
||||
ElementHandle waitForSelectorImpl(String selector, WaitForSelectorOptions options) {
|
||||
return waitForSelectorImpl(selector, options, false);
|
||||
}
|
||||
|
||||
@@ -982,7 +1057,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("omitReturnValue", omitReturnValue);
|
||||
JsonElement json = sendMessage("waitForSelector", params, timeout(options.timeout));
|
||||
JsonElement json = sendMessage("waitForSelector", params);
|
||||
JsonObject element = json.getAsJsonObject().getAsJsonObject("element");
|
||||
if (element == null) {
|
||||
return null;
|
||||
@@ -992,14 +1067,18 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public void waitForTimeout(double timeout) {
|
||||
withLogging("Frame.waitForTimeout", () -> waitForTimeoutImpl(timeout));
|
||||
}
|
||||
|
||||
void waitForTimeoutImpl(double timeout) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("waitTimeout", timeout);
|
||||
sendMessage("waitForTimeout", params, NO_TIMEOUT);
|
||||
params.addProperty("timeout", timeout);
|
||||
sendMessage("waitForTimeout", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(UrlMatcher.forGlob(page.context().baseUrl(), url, this.connection.localUtils, false), options);
|
||||
waitForURL(new UrlMatcher(page.context().baseUrl, url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1034,14 +1113,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
int queryCount(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
JsonObject result = sendMessage("queryCount", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = sendMessage("queryCount", params).getAsJsonObject();
|
||||
return result.get("value").getAsInt();
|
||||
}
|
||||
|
||||
void highlightImpl(String selector) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("highlight", params, NO_TIMEOUT);
|
||||
sendMessage("highlight", params);
|
||||
}
|
||||
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
@@ -1072,30 +1151,4 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
internalListeners.notify(InternalEventType.NAVIGATED, params);
|
||||
}
|
||||
}
|
||||
|
||||
protected double timeout(Double timeout) {
|
||||
if (page != null) {
|
||||
return page.timeoutSettings.timeout(timeout);
|
||||
}
|
||||
return new TimeoutSettings().timeout(timeout);
|
||||
}
|
||||
|
||||
protected double navigationTimeout(Double timeout) {
|
||||
if (page != null) {
|
||||
return page.timeoutSettings.navigationTimeout(timeout);
|
||||
}
|
||||
return new TimeoutSettings().navigationTimeout(timeout);
|
||||
}
|
||||
|
||||
FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
|
||||
return withTitle(title, () -> expect(expression, options));
|
||||
}
|
||||
|
||||
FrameExpectResult expect(String expression, FrameExpectOptions options) {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("expression", expression);
|
||||
JsonElement json = sendMessage("expect", params, options.timeout);
|
||||
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
import static com.microsoft.playwright.impl.LoggingSupport.*;
|
||||
import static com.microsoft.playwright.impl.Serialization.fromNameValues;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
@@ -42,7 +41,7 @@ public class HARRouter {
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("file", harFile.toString());
|
||||
JsonObject json = localUtils.sendMessage("harOpen", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = localUtils.sendMessage("harOpen", params).getAsJsonObject();
|
||||
if (json.has("error")) {
|
||||
throw new PlaywrightException(json.get("error").getAsString());
|
||||
}
|
||||
@@ -62,7 +61,7 @@ public class HARRouter {
|
||||
params.addProperty("postData", base64);
|
||||
}
|
||||
params.addProperty("isNavigationRequest", request.isNavigationRequest());
|
||||
JsonObject response = localUtils.sendMessage("harLookup", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject response = localUtils.sendMessage("harLookup", params).getAsJsonObject();
|
||||
|
||||
String action = response.get("action").getAsString();
|
||||
if ("redirect".equals(action)) {
|
||||
|
||||
@@ -41,58 +41,70 @@ public class JSHandleImpl extends ChannelOwner implements JSHandle {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
sendMessage("dispose");
|
||||
} catch (TargetClosedError e) {
|
||||
}
|
||||
withLogging("JSHandle.dispose", () -> {
|
||||
try {
|
||||
sendMessage("dispose");
|
||||
} catch (TargetClosedError e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpression", params, NO_TIMEOUT);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return withLogging("JSHandle.evaluate", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpression", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle evaluateHandle(String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params, NO_TIMEOUT);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString());
|
||||
return withLogging("JSHandle.evaluateHandle", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.addProperty("world", "main");
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, JSHandle> getProperties() {
|
||||
JsonObject json = sendMessage("getPropertyList").getAsJsonObject();
|
||||
Map<String, JSHandle> result = new HashMap<>();
|
||||
for (JsonElement e : json.getAsJsonArray("properties")) {
|
||||
JsonObject item = e.getAsJsonObject();
|
||||
JSHandle value = connection.getExistingObject(item.getAsJsonObject("value").get("guid").getAsString());
|
||||
result.put(item.get("name").getAsString(), value);
|
||||
}
|
||||
return result;
|
||||
return withLogging("JSHandle.getProperties", () -> {
|
||||
JsonObject json = sendMessage("getPropertyList").getAsJsonObject();
|
||||
Map<String, JSHandle> result = new HashMap<>();
|
||||
for (JsonElement e : json.getAsJsonArray("properties")) {
|
||||
JsonObject item = e.getAsJsonObject();
|
||||
JSHandle value = connection.getExistingObject(item.getAsJsonObject("value").get("guid").getAsString());
|
||||
result.put(item.get("name").getAsString(), value);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle getProperty(String propertyName) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", propertyName);
|
||||
JsonObject json = sendMessage("getProperty", params, NO_TIMEOUT).getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("handle").get("guid").getAsString());
|
||||
return withLogging("JSHandle.getProperty", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", propertyName);
|
||||
JsonObject json = sendMessage("getProperty", params).getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("handle").get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jsonValue() {
|
||||
JsonObject json = sendMessage("jsonValue").getAsJsonObject();
|
||||
SerializedValue value = gson().fromJson(json.get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return withLogging("JSHandle.jsonValue", () -> {
|
||||
JsonObject json = sendMessage("jsonValue").getAsJsonObject();
|
||||
SerializedValue value = gson().fromJson(json.get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,7 @@ class JsonPipe extends ChannelOwner implements Transport {
|
||||
checkIfClosed();
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("message", message);
|
||||
sendMessage("send", params, NO_TIMEOUT);
|
||||
sendMessage("send", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Keyboard;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class KeyboardImpl implements Keyboard {
|
||||
@@ -31,21 +30,25 @@ class KeyboardImpl implements Keyboard {
|
||||
|
||||
@Override
|
||||
public void down(String key) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("key", key);
|
||||
page.sendMessage("keyboardDown", params, NO_TIMEOUT);
|
||||
page.withLogging("Keyboard.down", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("key", key);
|
||||
page.sendMessage("keyboardDown", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertText(String text) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("text", text);
|
||||
page.sendMessage("keyboardInsertText", params, NO_TIMEOUT);
|
||||
page.withLogging("Keyboard.insertText", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("text", text);
|
||||
page.sendMessage("keyboardInsertText", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void press(String key, PressOptions options) {
|
||||
pressImpl(key, options);
|
||||
page.withLogging("Keyboard.press", () -> pressImpl(key, options));
|
||||
}
|
||||
|
||||
private void pressImpl(String key, PressOptions options) {
|
||||
@@ -54,12 +57,12 @@ class KeyboardImpl implements Keyboard {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("key", key);
|
||||
page.sendMessage("keyboardPress", params, NO_TIMEOUT);
|
||||
page.sendMessage("keyboardPress", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void type(String text, TypeOptions options) {
|
||||
typeImpl(text, options);
|
||||
page.withLogging("Keyboard.type", () -> typeImpl(text, options));
|
||||
}
|
||||
|
||||
private void typeImpl(String text, TypeOptions options) {
|
||||
@@ -68,13 +71,15 @@ class KeyboardImpl implements Keyboard {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("text", text);
|
||||
page.sendMessage("keyboardType", params, NO_TIMEOUT);
|
||||
page.sendMessage("keyboardType", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void up(String key) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("key", key);
|
||||
page.sendMessage("keyboardUp", params, NO_TIMEOUT);
|
||||
page.withLogging("Keyboard.up", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("key", key);
|
||||
page.sendMessage("keyboardUp", params);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ 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;
|
||||
|
||||
public class LocalUtils extends ChannelOwner {
|
||||
class LocalUtils extends ChannelOwner {
|
||||
LocalUtils(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
}
|
||||
|
||||
JsonArray deviceDescriptors() {
|
||||
@@ -41,13 +41,13 @@ public class LocalUtils extends ChannelOwner {
|
||||
params.addProperty("mode", appendMode ? "append" : "write");
|
||||
params.addProperty("stacksId", stacksId);
|
||||
params.addProperty("includeSources", includeSources);
|
||||
sendMessage("zip", params, NO_TIMEOUT);
|
||||
sendMessage("zip", params);
|
||||
}
|
||||
|
||||
void traceDiscarded(String stacksId) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("stacksId", stacksId);
|
||||
sendMessage("traceDiscarded", params, NO_TIMEOUT);
|
||||
sendMessage("traceDiscarded", params);
|
||||
}
|
||||
|
||||
String tracingStarted(String tracesDir, String traceName) {
|
||||
@@ -56,19 +56,7 @@ public class LocalUtils extends ChannelOwner {
|
||||
params.addProperty("tracesDir", "");
|
||||
}
|
||||
params.addProperty("traceName", traceName);
|
||||
JsonObject json = connection.localUtils().sendMessage("tracingStarted", params, NO_TIMEOUT).getAsJsonObject();
|
||||
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, NO_TIMEOUT).getAsJsonObject();
|
||||
String regex = json.get("regex").getAsString();
|
||||
return Pattern.compile(regex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.assertions.LocatorAssertions;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -30,39 +31,12 @@ import static com.microsoft.playwright.impl.Serialization.serializeArgument;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAssertions {
|
||||
LocatorImpl actualLocator;
|
||||
|
||||
public LocatorAssertionsImpl(Locator locator) {
|
||||
this(locator, false);
|
||||
}
|
||||
|
||||
private LocatorAssertionsImpl(Locator locator, boolean isNot) {
|
||||
super(isNot);
|
||||
this.actualLocator = (LocatorImpl) locator;
|
||||
}
|
||||
|
||||
@Override
|
||||
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
|
||||
return actualLocator.expect(expression, expectOptions, title);
|
||||
}
|
||||
|
||||
|
||||
@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), "Assert \"containsClass\"");
|
||||
}
|
||||
|
||||
@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), "Assert \"containsClass\"");
|
||||
super((LocatorImpl) locator, isNot);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,7 +46,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.matchSubstring = true;
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.text", expected, text, "Locator expected to contain text", convertType(options, FrameExpectOptions.class), "Assert \"containsText\"");
|
||||
expectImpl("to.have.text", expected, text, "Locator expected to contain text", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,7 +55,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.matchSubstring = true;
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.text", expected, pattern, "Locator expected to contain regex", convertType(options, FrameExpectOptions.class), "Assert \"containsText\"");
|
||||
expectImpl("to.have.text", expected, pattern, "Locator expected to contain regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -95,7 +69,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.normalizeWhiteSpace = true;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.contain.text.array", list, strings, "Locator expected to contain text", convertType(options, FrameExpectOptions.class), "Assert \"containsText\"");
|
||||
expectImpl("to.contain.text.array", list, strings, "Locator expected to contain text", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +82,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.normalizeWhiteSpace = true;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.contain.text.array", list, patterns, "Locator expected to contain text", convertType(options, FrameExpectOptions.class), "Assert \"containsText\"");
|
||||
expectImpl("to.contain.text.array", list, patterns, "Locator expected to contain text", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,7 +91,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleDescription\"");
|
||||
expectImpl("to.have.accessible.description", expected, description, "Locator expected to have accessible description", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,7 +99,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleDescription\"");
|
||||
expectImpl("to.have.accessible.description", expected, pattern, "Locator expected to have accessible description", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,7 +108,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleErrorMessage\"");
|
||||
expectImpl("to.have.accessible.error.message", expected, errorMessage, "Locator expected to have accessible error message", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,7 +116,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleErrorMessage\"");
|
||||
expectImpl("to.have.accessible.error.message", expected, pattern, "Locator expected to have accessible error message", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,7 +125,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleName\"");
|
||||
expectImpl("to.have.accessible.name", expected, name, "Locator expected to have accessible name", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,7 +133,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
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), "Assert \"hasAccessibleName\"");
|
||||
expectImpl("to.have.accessible.name", expected, pattern, "Locator expected to have accessible name", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,20 +161,20 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
if (expectedValue instanceof Pattern) {
|
||||
message += " matching regex";
|
||||
}
|
||||
expectImpl("to.have.attribute.value", expectedText, expectedValue, message, commonOptions, "Assert \"hasAttribute\"");
|
||||
expectImpl("to.have.attribute.value", expectedText, expectedValue, message, commonOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasClass(String text, HasClassOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = text;
|
||||
expectImpl("to.have.class", expected, text, "Locator expected to have class", convertType(options, FrameExpectOptions.class), "Assert \"hasClass\"");
|
||||
expectImpl("to.have.class", expected, text, "Locator expected to have class", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasClass(Pattern pattern, HasClassOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expectImpl("to.have.class", expected, pattern, "Locator expected to have class matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasClass\"");
|
||||
expectImpl("to.have.class", expected, pattern, "Locator expected to have class matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -211,7 +185,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.string = text;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.class.array", list, strings, "Locator expected to have class", convertType(options, FrameExpectOptions.class), "Assert \"hasClass\"");
|
||||
expectImpl("to.have.class.array", list, strings, "Locator expected to have class", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,7 +195,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.class.array", list, patterns, "Locator expected to have class matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasClass\"");
|
||||
expectImpl("to.have.class.array", list, patterns, "Locator expected to have class matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,7 +206,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
FrameExpectOptions commonOptions = convertType(options, FrameExpectOptions.class);
|
||||
commonOptions.expectedNumber = (double) count;
|
||||
List<ExpectedTextValue> expectedText = null;
|
||||
expectImpl("to.have.count", expectedText, count, "Locator expected to have count", commonOptions, "Assert \"hasCount\"");
|
||||
expectImpl("to.have.count", expectedText, count, "Locator expected to have count", commonOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -258,20 +232,20 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
if (expectedValue instanceof Pattern) {
|
||||
message += " matching regex";
|
||||
}
|
||||
expectImpl("to.have.css", expectedText, expectedValue, message, commonOptions, "Assert \"hasCSS\"");
|
||||
expectImpl("to.have.css", expectedText, expectedValue, message, commonOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasId(String id, HasIdOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = id;
|
||||
expectImpl("to.have.id", expected, id, "Locator expected to have ID", convertType(options, FrameExpectOptions.class), "Assert \"hasId\"");
|
||||
expectImpl("to.have.id", expected, id, "Locator expected to have ID", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasId(Pattern pattern, HasIdOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expectImpl("to.have.id", expected, pattern, "Locator expected to have ID matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasId\"");
|
||||
expectImpl("to.have.id", expected, pattern, "Locator expected to have ID matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,14 +257,14 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
commonOptions.expressionArg = name;
|
||||
commonOptions.expectedValue = serializeArgument(value);
|
||||
List<ExpectedTextValue> list = null;
|
||||
expectImpl("to.have.property", list, value, "Locator expected to have JavaScript property '" + name + "'", commonOptions, "Assert \"hasJSProperty\"");
|
||||
expectImpl("to.have.property", list, value, "Locator expected to have JavaScript property '" + name + "'", commonOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasRole(AriaRole role, HasRoleOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = role.toString().toLowerCase();
|
||||
expectImpl("to.have.role", expected, expected.string, "Locator expected to have role", convertType(options, FrameExpectOptions.class), "Assert \"hasRole\"");
|
||||
expectImpl("to.have.role", expected, expected.string, "Locator expected to have role", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -300,7 +274,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expected.matchSubstring = false;
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.text", expected, text, "Locator expected to have text", convertType(options, FrameExpectOptions.class), "Assert \"hasText\"");
|
||||
expectImpl("to.have.text", expected, text, "Locator expected to have text", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -310,7 +284,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
// Just match substring, same as containsText.
|
||||
expected.matchSubstring = true;
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.text", expected, pattern, "Locator expected to have text matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasText\"");
|
||||
expectImpl("to.have.text", expected, pattern, "Locator expected to have text matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -324,7 +298,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.normalizeWhiteSpace = true;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.text.array", list, strings, "Locator expected to have text", convertType(options, FrameExpectOptions.class), "Assert \"hasText\"");
|
||||
expectImpl("to.have.text.array", list, strings, "Locator expected to have text", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,20 +311,20 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.normalizeWhiteSpace = true;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.text.array", list, patterns, "Locator expected to have text matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasText\"");
|
||||
expectImpl("to.have.text.array", list, patterns, "Locator expected to have text matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasValue(String value, HasValueOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = value;
|
||||
expectImpl("to.have.value", expected, value, "Locator expected to have value", convertType(options, FrameExpectOptions.class), "Assert \"hasValue\"");
|
||||
expectImpl("to.have.value", expected, value, "Locator expected to have value", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasValue(Pattern pattern, HasValueOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expectImpl("to.have.value", expected, pattern, "Locator expected to have value matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasValue\"");
|
||||
expectImpl("to.have.value", expected, pattern, "Locator expected to have value matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -361,7 +335,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.string = text;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.values", list, values, "Locator expected to have values", convertType(options, FrameExpectOptions.class), "Assert \"hasValues\"");
|
||||
expectImpl("to.have.values", list, values, "Locator expected to have values", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -372,7 +346,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expected.matchSubstring = true;
|
||||
list.add(expected);
|
||||
}
|
||||
expectImpl("to.have.values", list, patterns, "Locator expected to have values matching regex", convertType(options, FrameExpectOptions.class), "Assert \"hasValues\"");
|
||||
expectImpl("to.have.values", list, patterns, "Locator expected to have values matching regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -382,7 +356,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
}
|
||||
FrameExpectOptions options = convertType(snapshotOptions, FrameExpectOptions.class);
|
||||
options.expectedValue = serializeArgument(expected);
|
||||
expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot", "Assert \"matchesAriaSnapshot\"");
|
||||
expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -410,12 +384,12 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
String message = "Locator expected to be";
|
||||
FrameExpectOptions expectOptions = convertType(options, FrameExpectOptions.class);
|
||||
expectOptions.expectedValue = serializeArgument(expectedValue);
|
||||
expectImpl("to.be.checked", expectOptions, expected, message, "Assert \"isChecked\"");
|
||||
expectImpl("to.be.checked", expectOptions, expected, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isDisabled(IsDisabledOptions options) {
|
||||
expectTrue("to.be.disabled", "Locator expected to be disabled", convertType(options, FrameExpectOptions.class), "Assert \"isDisabled\"");
|
||||
expectTrue("to.be.disabled", "Locator expected to be disabled", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -423,12 +397,12 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean editable = options == null || options.editable == null || options.editable == true;
|
||||
String message = "Locator expected to be " + (editable ? "editable" : "readonly");
|
||||
expectTrue(editable ? "to.be.editable" : "to.be.readonly", message, frameOptions, "Assert \"isEditable\"");
|
||||
expectTrue(editable ? "to.be.editable" : "to.be.readonly", message, frameOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isEmpty(IsEmptyOptions options) {
|
||||
expectTrue("to.be.empty", "Locator expected to be empty", convertType(options, FrameExpectOptions.class), "Assert \"isEmpty\"");
|
||||
expectTrue("to.be.empty", "Locator expected to be empty", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -436,17 +410,17 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean enabled = options == null || options.enabled == null || options.enabled == true;
|
||||
String message = "Locator expected to be " + (enabled ? "enabled" : "disabled");
|
||||
expectTrue(enabled ? "to.be.enabled" : "to.be.disabled", message, frameOptions, "Assert \"isEnabled\"");
|
||||
expectTrue(enabled ? "to.be.enabled" : "to.be.disabled", message, frameOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isFocused(IsFocusedOptions options) {
|
||||
expectTrue("to.be.focused", "Locator expected to be focused", convertType(options, FrameExpectOptions.class), "Assert \"isFocused\"");
|
||||
expectTrue("to.be.focused", "Locator expected to be focused", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isHidden(IsHiddenOptions options) {
|
||||
expectTrue("to.be.hidden", "Locator expected to be hidden", convertType(options, FrameExpectOptions.class), "Assert \"isHidden\"");
|
||||
expectTrue("to.be.hidden", "Locator expected to be hidden", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -455,7 +429,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
if (options != null && options.ratio != null) {
|
||||
expectOptions.expectedNumber = options.ratio;
|
||||
}
|
||||
expectTrue("to.be.in.viewport", "Locator expected to be in viewport", expectOptions, "Assert \"isInViewport\"");
|
||||
expectTrue("to.be.in.viewport", "Locator expected to be in viewport", expectOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -463,12 +437,12 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean visible = options == null || options.visible == null || options.visible == true;
|
||||
String message = "Locator expected to be " + (visible ? "visible" : "hidden");
|
||||
expectTrue(visible ? "to.be.visible" : "to.be.hidden", message, frameOptions, "Assert \"isVisible\"");
|
||||
expectTrue(visible ? "to.be.visible" : "to.be.hidden", message, frameOptions);
|
||||
}
|
||||
|
||||
private void expectTrue(String expression, String message, FrameExpectOptions options, String title) {
|
||||
private void expectTrue(String expression, String message, FrameExpectOptions options) {
|
||||
List<ExpectedTextValue> expectedText = null;
|
||||
expectImpl(expression, expectedText, null, message, options, title);
|
||||
expectImpl(expression, expectedText, null, message, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -481,6 +455,6 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean attached = options == null || options.attached == null || options.attached == true;
|
||||
String message = "Locator expected to be " + (attached ? "attached" : "detached");
|
||||
expectTrue(attached ? "to.be.attached" : "to.be.detached", message, frameOptions, "Assert \"isAttached\"");
|
||||
expectTrue(attached ? "to.be.attached" : "to.be.detached", message, frameOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,25 +67,27 @@ class LocatorImpl implements Locator {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
private <R, O> R withElement(BiFunction<ElementHandle, O, R> callback, O options, String title) {
|
||||
return frame.withTitle(title, () -> {
|
||||
ElementHandleOptions handleOptions = convertType(options, ElementHandleOptions.class);
|
||||
// TODO: support deadline based timeout
|
||||
// Double timeout = null;
|
||||
// if (handleOptions != null) {
|
||||
// timeout = handleOptions.timeout;
|
||||
// }
|
||||
// timeout = frame.page.timeoutSettings.timeout(timeout);
|
||||
// long deadline = System.nanoTime() + (long) timeout.doubleValue() * 1_000_000;
|
||||
ElementHandle handle = elementHandle(handleOptions);
|
||||
try {
|
||||
return callback.apply(handle, options);
|
||||
} finally {
|
||||
if (handle != null) {
|
||||
handle.dispose();
|
||||
}
|
||||
private static String escapeWithQuotes(String text) {
|
||||
return gson().toJson(text);
|
||||
}
|
||||
|
||||
private <R, O> R withElement(BiFunction<ElementHandle, O, R> callback, O options) {
|
||||
ElementHandleOptions handleOptions = convertType(options, ElementHandleOptions.class);
|
||||
// TODO: support deadline based timeout
|
||||
// Double timeout = null;
|
||||
// if (handleOptions != null) {
|
||||
// timeout = handleOptions.timeout;
|
||||
// }
|
||||
// timeout = frame.page.timeoutSettings.timeout(timeout);
|
||||
// long deadline = System.nanoTime() + (long) timeout.doubleValue() * 1_000_000;
|
||||
ElementHandle handle = elementHandle(handleOptions);
|
||||
try {
|
||||
return callback.apply(handle, options);
|
||||
} finally {
|
||||
if (handle != null) {
|
||||
handle.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,29 +120,37 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@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, frame.timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject result = frame.sendMessage("ariaSnapshot", params).getAsJsonObject();
|
||||
return result.get("snapshot").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blur(BlurOptions options) {
|
||||
frame.withLogging("Locator.blur", () -> blurImpl(options));
|
||||
}
|
||||
|
||||
private void blurImpl(BlurOptions options) {
|
||||
if (options == null) {
|
||||
options = new BlurOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("strict", true);
|
||||
frame.sendMessage("blur", params, frame.timeout(options.timeout));
|
||||
frame.sendMessage("blur", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox boundingBox(BoundingBoxOptions options) {
|
||||
return withElement((h, o) -> h.boundingBox(), options, "Bounding Box");
|
||||
return withElement((h, o) -> h.boundingBox(), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,7 +163,7 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@Override
|
||||
public void clear(ClearOptions options) {
|
||||
frame.withTitle("Clear", () -> fill("", convertType(options, FillOptions.class)));
|
||||
fill("", convertType(options, FillOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,11 +179,6 @@ class LocatorImpl implements Locator {
|
||||
return frame.queryCount(selector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator describe(String description) {
|
||||
return locator(describeSelector(description));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dblclick(DblclickOptions options) {
|
||||
if (options == null) {
|
||||
@@ -223,7 +228,7 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@Override
|
||||
public Object evaluate(String expression, Object arg, EvaluateOptions options) {
|
||||
return withElement((h, o) -> h.evaluate(expression, arg), options, "Evaluate");
|
||||
return withElement((h, o) -> h.evaluate(expression, arg), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,7 +238,7 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@Override
|
||||
public JSHandle evaluateHandle(String expression, Object arg, EvaluateHandleOptions options) {
|
||||
return withElement((h, o) -> h.evaluateHandle(expression, arg), options, "Evaluate");
|
||||
return withElement((h, o) -> h.evaluateHandle(expression, arg), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -478,7 +483,7 @@ class LocatorImpl implements Locator {
|
||||
|
||||
@Override
|
||||
public byte[] screenshot(ScreenshotOptions options) {
|
||||
return withElement((h, o) -> h.screenshot(o), convertType(options, ElementHandle.ScreenshotOptions.class), "Screenshot");
|
||||
return withElement((h, o) -> h.screenshot(o), convertType(options, ElementHandle.ScreenshotOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -486,7 +491,7 @@ class LocatorImpl implements Locator {
|
||||
withElement((h, o) -> {
|
||||
h.scrollIntoViewIfNeeded(o);
|
||||
return null;
|
||||
}, convertType(options, ElementHandle.ScrollIntoViewIfNeededOptions.class), "Scroll into view");
|
||||
}, convertType(options, ElementHandle.ScrollIntoViewIfNeededOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -542,7 +547,7 @@ class LocatorImpl implements Locator {
|
||||
withElement((h, o) -> {
|
||||
h.selectText(o);
|
||||
return null;
|
||||
}, convertType(options, ElementHandle.SelectTextOptions.class), "Select text");
|
||||
}, convertType(options, ElementHandle.SelectTextOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -622,7 +627,11 @@ class LocatorImpl implements Locator {
|
||||
if (options == null) {
|
||||
options = new WaitForOptions();
|
||||
}
|
||||
frame.waitForSelectorImpl(selector, convertType(options, Frame.WaitForSelectorOptions.class).setStrict(true), true);
|
||||
waitForImpl(options);
|
||||
}
|
||||
|
||||
private void waitForImpl(WaitForOptions options) {
|
||||
frame.withLogging("Locator.waitFor", () -> frame.waitForSelectorImpl(selector, convertType(options, Frame.WaitForSelectorOptions.class).setStrict(true), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -644,9 +653,8 @@ class LocatorImpl implements Locator {
|
||||
return frame.hashCode() ^ selector.hashCode();
|
||||
}
|
||||
|
||||
FrameExpectResult expect(String expression, FrameExpectOptions options, String title) {
|
||||
options.selector = selector;
|
||||
return frame.expect(expression, options, title);
|
||||
FrameExpectResult expect(String expression, FrameExpectOptions options) {
|
||||
return frame.withLogging("Locator.expect", () -> expectImpl(expression, options));
|
||||
}
|
||||
|
||||
JsonObject toProtocol() {
|
||||
@@ -655,4 +663,13 @@ class LocatorImpl implements Locator {
|
||||
result.addProperty("selector", selector);
|
||||
return result;
|
||||
}
|
||||
|
||||
private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("expression", expression);
|
||||
JsonElement json = frame.sendMessage("expect", params);
|
||||
FrameExpectResult result = gson().fromJson(json, FrameExpectResult.class);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,9 @@ public class LocatorUtils {
|
||||
return "internal:attr=[" + attrName + "=" + escapeForAttributeSelector(value, exact) + "]";
|
||||
}
|
||||
|
||||
static String describeSelector(String description) {
|
||||
return "internal:describe=" + gson().toJson(description);
|
||||
}
|
||||
|
||||
static String getByTestIdSelector(Object testId, PlaywrightImpl playwright) {
|
||||
return getByAttributeTextSelector(playwright.selectors.testIdAttributeName, testId, true);
|
||||
String testIdAttributeName = ((SharedSelectors) playwright.selectors()).testIdAttributeName;
|
||||
return getByAttributeTextSelector(testIdAttributeName, testId, true);
|
||||
}
|
||||
|
||||
static String getByAltTextSelector(Object text, Locator.GetByAltTextOptions options) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.microsoft.playwright.impl;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class LoggingSupport {
|
||||
private static final boolean isEnabled;
|
||||
@@ -30,6 +31,29 @@ class LoggingSupport {
|
||||
private static final DateTimeFormatter timestampFormat = DateTimeFormatter.ofPattern(
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneId.of("UTC"));
|
||||
|
||||
void withLogging(String apiName, Runnable code) {
|
||||
withLogging(apiName, () -> {
|
||||
code.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
<T> T withLogging(String apiName, Supplier<T> code) {
|
||||
if (isEnabled) {
|
||||
logApi("=> " + apiName + " started");
|
||||
}
|
||||
boolean success = false;
|
||||
try {
|
||||
T result = code.get();
|
||||
success = true;
|
||||
return result;
|
||||
} finally {
|
||||
if (isEnabled) {
|
||||
logApi("<= " + apiName + (success ? " succeeded" : " failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void logWithTimestamp(String message) {
|
||||
// This matches log format produced by the server.
|
||||
String timestamp = ZonedDateTime.now().format(timestampFormat);
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Mouse;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
@@ -32,18 +31,22 @@ class MouseImpl implements Mouse {
|
||||
|
||||
@Override
|
||||
public void click(double x, double y, ClickOptions options) {
|
||||
page.withLogging("Mouse.click", () -> clickImpl(x, y, options));
|
||||
}
|
||||
|
||||
private void clickImpl(double x, double y, ClickOptions options) {
|
||||
if (options == null) {
|
||||
options = new ClickOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("x", x);
|
||||
params.addProperty("y", y);
|
||||
page.sendMessage("mouseClick", params, NO_TIMEOUT);
|
||||
page.sendMessage("mouseClick", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dblclick(double x, double y, DblclickOptions options) {
|
||||
page.withTitle("Double click", () -> dblclickImpl(x, y, options));
|
||||
page.withLogging("Mouse.dblclick", () -> dblclickImpl(x, y, options));
|
||||
}
|
||||
|
||||
private void dblclickImpl(double x, double y, DblclickOptions options) {
|
||||
@@ -59,38 +62,52 @@ class MouseImpl implements Mouse {
|
||||
|
||||
@Override
|
||||
public void down(DownOptions options) {
|
||||
page.withLogging("Mouse.down", () -> downImpl(options));
|
||||
}
|
||||
|
||||
private void downImpl(DownOptions options) {
|
||||
if (options == null) {
|
||||
options = new DownOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
page.sendMessage("mouseDown", params, NO_TIMEOUT);
|
||||
page.sendMessage("mouseDown", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(double x, double y, MoveOptions options) {
|
||||
page.withLogging("Mouse.move", () -> moveImpl(x, y, options));
|
||||
}
|
||||
|
||||
private void moveImpl(double x, double y, MoveOptions options) {
|
||||
if (options == null) {
|
||||
options = new MoveOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("x", x);
|
||||
params.addProperty("y", y);
|
||||
page.sendMessage("mouseMove", params, NO_TIMEOUT);
|
||||
page.sendMessage("mouseMove", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void up(UpOptions options) {
|
||||
if (options == null) {
|
||||
options = new UpOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
page.sendMessage("mouseUp", params, NO_TIMEOUT);
|
||||
page.withLogging("Mouse.up", () -> upImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wheel(double deltaX, double deltaY) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("deltaX", deltaX);
|
||||
params.addProperty("deltaY", deltaY);
|
||||
page.sendMessage("mouseWheel", params, NO_TIMEOUT);
|
||||
page.withLogging("Mouse.wheel", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("deltaX", deltaX);
|
||||
params.addProperty("deltaY", deltaY);
|
||||
page.sendMessage("mouseWheel", params);
|
||||
});
|
||||
}
|
||||
|
||||
private void upImpl(UpOptions options) {
|
||||
if (options == null) {
|
||||
options = new UpOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
page.sendMessage("mouseUp", params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.microsoft.playwright.assertions.PageAssertions;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorAssertionsImpl.shouldIgnoreCase;
|
||||
import static com.microsoft.playwright.impl.UrlMatcher.resolveUrl;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
@@ -32,45 +33,39 @@ public class PageAssertionsImpl extends AssertionsBase implements PageAssertions
|
||||
}
|
||||
|
||||
private PageAssertionsImpl(Page page, boolean isNot) {
|
||||
super(isNot);
|
||||
super((LocatorImpl) page.locator(":root"), isNot);
|
||||
this.actualPage = (PageImpl) page;
|
||||
}
|
||||
|
||||
@Override
|
||||
FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title) {
|
||||
FrameImpl frame = (FrameImpl) actualPage.mainFrame();
|
||||
return frame.expect(expression, expectOptions, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasTitle(String title, HasTitleOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = title;
|
||||
expected.normalizeWhiteSpace = true;
|
||||
expectImpl("to.have.title", expected, title, "Page title expected to be", convertType(options, FrameExpectOptions.class), "Assert \"hasTitle\"");
|
||||
expectImpl("to.have.title", expected, title, "Page title expected to be", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasTitle(Pattern pattern, HasTitleOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expectImpl("to.have.title", expected, pattern, "Page title expected to match regex", convertType(options, FrameExpectOptions.class), "Assert \"hasTitle\"");
|
||||
expectImpl("to.have.title", expected, pattern, "Page title expected to match regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasURL(String url, HasURLOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
if (actualPage.context().baseUrl() != null) {
|
||||
url = resolveUrl(actualPage.context().baseUrl(), url);
|
||||
if (actualPage.context().baseUrl != null) {
|
||||
url = resolveUrl(actualPage.context().baseUrl, url);
|
||||
}
|
||||
expected.string = url;
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
expectImpl("to.have.url", expected, url, "Page URL expected to be", convertType(options, FrameExpectOptions.class), "Assert \"hasURL\"");
|
||||
expectImpl("to.have.url", expected, url, "Page URL expected to be", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasURL(Pattern pattern, HasURLOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expectImpl("to.have.url", expected, pattern, "Page URL expected to match regex", convertType(options, FrameExpectOptions.class), "Assert \"hasURL\"");
|
||||
expectImpl("to.have.url", expected, pattern, "Page URL expected to match regex", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -95,7 +95,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
BrowserContextImpl ownedContext;
|
||||
private boolean isClosed;
|
||||
final Set<Worker> workers = new HashSet<>();
|
||||
protected final TimeoutSettings timeoutSettings;
|
||||
private final TimeoutSettings timeoutSettings;
|
||||
private VideoImpl video;
|
||||
private final PageImpl opener;
|
||||
private String closeReason;
|
||||
@@ -546,7 +546,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
ownedContext.close();
|
||||
} else {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("close", params, NO_TIMEOUT);
|
||||
sendMessage("close", params);
|
||||
}
|
||||
} catch (PlaywrightException exception) {
|
||||
if (isSafeCloseError(exception) && (options.runBeforeUnload == null || !options.runBeforeUnload)) {
|
||||
@@ -558,13 +558,13 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public ElementHandle querySelector(String selector, QuerySelectorOptions options) {
|
||||
return mainFrame.querySelector(
|
||||
selector, convertType(options, Frame.QuerySelectorOptions.class));
|
||||
return withLogging("Page.querySelector", () -> mainFrame.querySelectorImpl(
|
||||
selector, convertType(options, Frame.QuerySelectorOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ElementHandle> querySelectorAll(String selector) {
|
||||
return mainFrame.querySelectorAll(selector);
|
||||
return withLogging("Page.querySelectorAll", () -> mainFrame.querySelectorAllImpl(selector));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -580,15 +580,17 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return;
|
||||
}
|
||||
AddLocatorHandlerOptions finalOptions = options;
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", locatorImpl.selector);
|
||||
if (finalOptions.noWaitAfter != null && finalOptions.noWaitAfter) {
|
||||
params.addProperty("noWaitAfter", true);
|
||||
}
|
||||
params.addProperty("selector", locatorImpl.selector);
|
||||
JsonObject json = (JsonObject) sendMessage("registerLocatorHandler", params, NO_TIMEOUT);
|
||||
int uid = json.get("uid").getAsInt();
|
||||
locatorHandlers.put(uid, new LocatorHandler(locator, handler, finalOptions.times));
|
||||
withLogging("Page.addLocatorHandler", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("selector", locatorImpl.selector);
|
||||
if (finalOptions.noWaitAfter != null && finalOptions.noWaitAfter) {
|
||||
params.addProperty("noWaitAfter", true);
|
||||
}
|
||||
params.addProperty("selector", locatorImpl.selector);
|
||||
JsonObject json = (JsonObject) sendMessage("registerLocatorHandler", params);
|
||||
int uid = json.get("uid").getAsInt();
|
||||
locatorHandlers.put(uid, new LocatorHandler(locator, handler, finalOptions.times));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -599,7 +601,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("uid", entry.getKey());
|
||||
try {
|
||||
sendMessage("unregisterLocatorHandler", params, NO_TIMEOUT);
|
||||
sendMessage("unregisterLocatorHandler", params);
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
}
|
||||
@@ -624,65 +626,71 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Object evalOnSelector(String selector, String pageFunction, Object arg, EvalOnSelectorOptions options) {
|
||||
return mainFrame.evalOnSelectorImpl(
|
||||
selector, pageFunction, arg, convertType(options, Frame.EvalOnSelectorOptions.class));
|
||||
return withLogging("Page.evalOnSelector", () -> mainFrame.evalOnSelectorImpl(
|
||||
selector, pageFunction, arg, convertType(options, Frame.EvalOnSelectorOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evalOnSelectorAll(String selector, String pageFunction, Object arg) {
|
||||
return mainFrame.evalOnSelectorAllImpl(selector, pageFunction, arg);
|
||||
return withLogging("Page.evalOnSelectorAll", () -> mainFrame.evalOnSelectorAllImpl(selector, pageFunction, arg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInitScript(String script) {
|
||||
addInitScriptImpl(script);
|
||||
withLogging("Page.addInitScript", () -> addInitScriptImpl(script));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInitScript(Path path) {
|
||||
try {
|
||||
byte[] bytes = readAllBytes(path);
|
||||
String script = addSourceUrlToScript(new String(bytes, UTF_8), path);
|
||||
addInitScriptImpl(script);
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read script from file", e);
|
||||
}
|
||||
withLogging("Page.addInitScript", () -> {
|
||||
try {
|
||||
byte[] bytes = readAllBytes(path);
|
||||
String script = addSourceUrlToScript(new String(bytes, UTF_8), path);
|
||||
addInitScriptImpl(script);
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read script from file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addInitScriptImpl(String script) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("source", script);
|
||||
sendMessage("addInitScript", params, NO_TIMEOUT);
|
||||
sendMessage("addInitScript", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandle addScriptTag(AddScriptTagOptions options) {
|
||||
return mainFrame.addScriptTagImpl(convertType(options, Frame.AddScriptTagOptions.class));
|
||||
return withLogging("Page.addScriptTag",
|
||||
() -> mainFrame.addScriptTagImpl(convertType(options, Frame.AddScriptTagOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandle addStyleTag(AddStyleTagOptions options) {
|
||||
return mainFrame.addStyleTagImpl(convertType(options, Frame.AddStyleTagOptions.class));
|
||||
return withLogging("Page.addStyleTag",
|
||||
() -> mainFrame.addStyleTagImpl(convertType(options, Frame.AddStyleTagOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bringToFront() {
|
||||
sendMessage("bringToFront");
|
||||
withLogging("Page.bringToFront", () -> sendMessage("bringToFront"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void check(String selector, CheckOptions options) {
|
||||
mainFrame.check(selector, convertType(options, Frame.CheckOptions.class));
|
||||
withLogging("Page.check",
|
||||
() -> mainFrame.checkImpl(selector, convertType(options, Frame.CheckOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(String selector, ClickOptions options) {
|
||||
mainFrame.clickImpl(selector, convertType(options, Frame.ClickOptions.class));
|
||||
withLogging("Page.click",
|
||||
() -> mainFrame.clickImpl(selector, convertType(options, Frame.ClickOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String content() {
|
||||
return mainFrame.content();
|
||||
return withLogging("Page.content", () -> mainFrame.contentImpl());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -692,17 +700,19 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void dblclick(String selector, DblclickOptions options) {
|
||||
mainFrame.dblclick(selector, convertType(options, Frame.DblclickOptions.class));
|
||||
withLogging("Page.dblclick",
|
||||
() -> mainFrame.dblclickImpl(selector, convertType(options, Frame.DblclickOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options) {
|
||||
mainFrame.dispatchEvent(selector, type, eventInit, convertType(options, Frame.DispatchEventOptions.class));
|
||||
withLogging("Page.dispatchEvent",
|
||||
() -> mainFrame.dispatchEventImpl(selector, type, eventInit, convertType(options, Frame.DispatchEventOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emulateMedia(EmulateMediaOptions options) {
|
||||
emulateMediaImpl(options);
|
||||
withLogging("Page.emulateMedia", () -> emulateMediaImpl(options));
|
||||
}
|
||||
|
||||
private void emulateMediaImpl(EmulateMediaOptions options) {
|
||||
@@ -710,22 +720,22 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
options = new EmulateMediaOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("emulateMedia", params, NO_TIMEOUT);
|
||||
sendMessage("emulateMedia", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(String expression, Object arg) {
|
||||
return mainFrame.evaluate(expression, arg);
|
||||
return withLogging("Page.evaluate", () -> mainFrame.evaluateImpl(expression, arg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle evaluateHandle(String pageFunction, Object arg) {
|
||||
return mainFrame.evaluateHandle(pageFunction, arg);
|
||||
return withLogging("Page.evaluateHandle", () -> mainFrame.evaluateHandleImpl(pageFunction, arg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeBinding(String name, BindingCallback playwrightBinding, ExposeBindingOptions options) {
|
||||
exposeBindingImpl(name, playwrightBinding, options);
|
||||
withLogging("Page.exposeBinding", () -> exposeBindingImpl(name, playwrightBinding, options));
|
||||
}
|
||||
|
||||
private void exposeBindingImpl(String name, BindingCallback playwrightBinding, ExposeBindingOptions options) {
|
||||
@@ -742,22 +752,25 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
if (options != null && options.handle != null && options.handle) {
|
||||
params.addProperty("needsHandle", true);
|
||||
}
|
||||
sendMessage("exposeBinding", params, NO_TIMEOUT);
|
||||
sendMessage("exposeBinding", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeFunction(String name, FunctionCallback playwrightFunction) {
|
||||
exposeBindingImpl(name, (BindingCallback.Source source, Object... args) -> playwrightFunction.call(args), null);
|
||||
withLogging("Page.exposeFunction",
|
||||
() -> exposeBindingImpl(name, (BindingCallback.Source source, Object... args) -> playwrightFunction.call(args), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(String selector, String value, FillOptions options) {
|
||||
mainFrame.fill(selector, value, convertType(options, Frame.FillOptions.class));
|
||||
withLogging("Page.fill",
|
||||
() -> mainFrame.fillImpl(selector, value, convertType(options, Frame.FillOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focus(String selector, FocusOptions options) {
|
||||
mainFrame.focus(selector, convertType(options, Frame.FocusOptions.class));
|
||||
withLogging("Page.focus",
|
||||
() -> mainFrame.focusImpl(selector, convertType(options, Frame.FocusOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -772,7 +785,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Frame frameByUrl(String glob) {
|
||||
return frameFor(UrlMatcher.forGlob(browserContext.baseUrl(), glob, this.connection.localUtils, false));
|
||||
return frameFor(new UrlMatcher(browserContext.baseUrl, glob));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -806,77 +819,89 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public String getAttribute(String selector, String name, GetAttributeOptions options) {
|
||||
return mainFrame.getAttributeImpl(selector, name, convertType(options, Frame.GetAttributeOptions.class));
|
||||
return withLogging("Page.getAttribute",
|
||||
() -> mainFrame.getAttributeImpl(selector, name, convertType(options, Frame.GetAttributeOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(String text, GetByAltTextOptions options) {
|
||||
return mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class));
|
||||
return withLogging("Page.getAttribute",
|
||||
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
|
||||
return mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class));
|
||||
return withLogging("Page.getByAltText",
|
||||
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(String text, GetByLabelOptions options) {
|
||||
return mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class));
|
||||
return withLogging("Page.getByLabel",
|
||||
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
|
||||
return mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class));
|
||||
return withLogging("Page.getByLabel",
|
||||
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
|
||||
return mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class));
|
||||
return withLogging("Page.getByPlaceholder",
|
||||
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
|
||||
return mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class));
|
||||
return withLogging("Page.getByPlaceholder",
|
||||
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
|
||||
return mainFrame.getByRole(role, convertType(options, Frame.GetByRoleOptions.class));
|
||||
return withLogging("Page.getByRole",
|
||||
() -> mainFrame.getByRole(role, convertType(options, Frame.GetByRoleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(String testId) {
|
||||
return mainFrame.getByTestId(testId);
|
||||
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(Pattern testId) {
|
||||
return mainFrame.getByTestId(testId);
|
||||
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(String text, GetByTextOptions options) {
|
||||
return mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class));
|
||||
return withLogging("Page.getByText",
|
||||
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(Pattern text, GetByTextOptions options) {
|
||||
return mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class));
|
||||
return withLogging("Page.getByText",
|
||||
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(String text, GetByTitleOptions options) {
|
||||
return mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class));
|
||||
return withLogging("Page.getByTitle",
|
||||
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
|
||||
return mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class));
|
||||
return withLogging("Page.getByTitle",
|
||||
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response goBack(GoBackOptions options) {
|
||||
return goBackImpl(options);
|
||||
return withLogging("Page.goBack", () -> goBackImpl(options));
|
||||
}
|
||||
|
||||
Response goBackImpl(GoBackOptions options) {
|
||||
@@ -884,7 +909,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
options = new GoBackOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonObject json = sendMessage("goBack", params, timeoutSettings.navigationTimeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("goBack", params).getAsJsonObject();
|
||||
if (json.has("response")) {
|
||||
return connection.getExistingObject(json.getAsJsonObject("response").get("guid").getAsString());
|
||||
}
|
||||
@@ -893,7 +918,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Response goForward(GoForwardOptions options) {
|
||||
return goForwardImpl(options);
|
||||
return withLogging("Page.goForward", () -> goForwardImpl(options));
|
||||
}
|
||||
|
||||
Response goForwardImpl(GoForwardOptions options) {
|
||||
@@ -901,7 +926,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
options = new GoForwardOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonObject json = sendMessage("goForward", params, timeoutSettings.navigationTimeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("goForward", params).getAsJsonObject();
|
||||
if (json.has("response")) {
|
||||
return connection.getExistingObject(json.getAsJsonObject("response").get("guid").getAsString());
|
||||
}
|
||||
@@ -910,42 +935,46 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void requestGC() {
|
||||
sendMessage("requestGC");
|
||||
withLogging("Page.requestGC", () -> sendMessage("requestGC"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseImpl navigate(String url, NavigateOptions options) {
|
||||
return mainFrame.navigateImpl(url, convertType(options, Frame.NavigateOptions.class));
|
||||
return withLogging("Page.navigate", () -> mainFrame.navigateImpl(url, convertType(options, Frame.NavigateOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hover(String selector, HoverOptions options) {
|
||||
mainFrame.hoverImpl(selector, convertType(options, Frame.HoverOptions.class));
|
||||
withLogging("Page.hover", () -> mainFrame.hoverImpl(selector, convertType(options, Frame.HoverOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dragAndDrop(String source, String target, DragAndDropOptions options) {
|
||||
mainFrame.dragAndDropImpl(source, target, convertType(options, Frame.DragAndDropOptions.class));
|
||||
withLogging("Page.dragAndDrop", () -> mainFrame.dragAndDropImpl(source, target, convertType(options, Frame.DragAndDropOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerHTML(String selector, InnerHTMLOptions options) {
|
||||
return mainFrame.innerHTMLImpl(selector, convertType(options, Frame.InnerHTMLOptions.class));
|
||||
return withLogging("Page.innerHTML",
|
||||
() -> mainFrame.innerHTMLImpl(selector, convertType(options, Frame.InnerHTMLOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String innerText(String selector, InnerTextOptions options) {
|
||||
return mainFrame.innerTextImpl(selector, convertType(options, Frame.InnerTextOptions.class));
|
||||
return withLogging("Page.innerText",
|
||||
() -> mainFrame.innerTextImpl(selector, convertType(options, Frame.InnerTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputValue(String selector, InputValueOptions options) {
|
||||
return mainFrame.inputValueImpl(selector, convertType(options, Frame.InputValueOptions.class));
|
||||
return withLogging("Page.inputValue",
|
||||
() -> mainFrame.inputValueImpl(selector, convertType(options, Frame.InputValueOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked(String selector, IsCheckedOptions options) {
|
||||
return mainFrame.isCheckedImpl(selector, convertType(options, Frame.IsCheckedOptions.class));
|
||||
return withLogging("Page.isChecked",
|
||||
() -> mainFrame.isCheckedImpl(selector, convertType(options, Frame.IsCheckedOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -955,27 +984,32 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public boolean isDisabled(String selector, IsDisabledOptions options) {
|
||||
return mainFrame.isDisabledImpl(selector, convertType(options, Frame.IsDisabledOptions.class));
|
||||
return withLogging("Page.isDisabled",
|
||||
() -> mainFrame.isDisabledImpl(selector, convertType(options, Frame.IsDisabledOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(String selector, IsEditableOptions options) {
|
||||
return mainFrame.isEditableImpl(selector, convertType(options, Frame.IsEditableOptions.class));
|
||||
return withLogging("Page.isEditable",
|
||||
() -> mainFrame.isEditableImpl(selector, convertType(options, Frame.IsEditableOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(String selector, IsEnabledOptions options) {
|
||||
return mainFrame.isEnabledImpl(selector, convertType(options, Frame.IsEnabledOptions.class));
|
||||
return withLogging("Page.isEnabled",
|
||||
() -> mainFrame.isEnabledImpl(selector, convertType(options, Frame.IsEnabledOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden(String selector, IsHiddenOptions options) {
|
||||
return mainFrame.isHiddenImpl(selector, convertType(options, Frame.IsHiddenOptions.class));
|
||||
return withLogging("Page.isHidden",
|
||||
() -> mainFrame.isHiddenImpl(selector, convertType(options, Frame.IsHiddenOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(String selector, IsVisibleOptions options) {
|
||||
return mainFrame.isVisibleImpl(selector, convertType(options, Frame.IsVisibleOptions.class));
|
||||
return withLogging("Page.isVisible",
|
||||
() -> mainFrame.isVisibleImpl(selector, convertType(options, Frame.IsVisibleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1008,21 +1042,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
Double defaultNavigationTimeout = browserContext.timeoutSettings.defaultNavigationTimeout();
|
||||
Double defaultTimeout = browserContext.timeoutSettings.defaultTimeout();
|
||||
browserContext.setDefaultNavigationTimeout(0.0);
|
||||
browserContext.setDefaultTimeout(0.0);
|
||||
try {
|
||||
runUntil(() -> {}, new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)));
|
||||
} finally {
|
||||
browserContext.setDefaultNavigationTimeout(defaultNavigationTimeout);
|
||||
browserContext.setDefaultTimeout(defaultTimeout);
|
||||
}
|
||||
withLogging("Page.pause", () -> {
|
||||
Double defaultNavigationTimeout = browserContext.timeoutSettings.defaultNavigationTimeout();
|
||||
Double defaultTimeout = browserContext.timeoutSettings.defaultTimeout();
|
||||
browserContext.setDefaultNavigationTimeoutImpl(0.0);
|
||||
browserContext.setDefaultTimeoutImpl(0.0);
|
||||
try {
|
||||
runUntil(() -> {}, new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)));
|
||||
} finally {
|
||||
browserContext.setDefaultNavigationTimeoutImpl(defaultNavigationTimeout);
|
||||
browserContext.setDefaultTimeoutImpl(defaultTimeout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] pdf(PdfOptions options) {
|
||||
return pdfImpl(options);
|
||||
return withLogging("Page.pdf", () -> pdfImpl(options));
|
||||
}
|
||||
|
||||
private byte[] pdfImpl(PdfOptions options) {
|
||||
@@ -1031,7 +1067,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.remove("path");
|
||||
JsonObject json = sendMessage("pdf", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("pdf", params).getAsJsonObject();
|
||||
byte[] buffer = Base64.getDecoder().decode(json.get("pdf").getAsString());
|
||||
if (options.path != null) {
|
||||
Utils.writeToFile(buffer, options.path);
|
||||
@@ -1041,12 +1077,13 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void press(String selector, String key, PressOptions options) {
|
||||
mainFrame.pressImpl(selector, key, convertType(options, Frame.PressOptions.class));
|
||||
withLogging("Page.press",
|
||||
() -> mainFrame.pressImpl(selector, key, convertType(options, Frame.PressOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response reload(ReloadOptions options) {
|
||||
return reloadImpl(options);
|
||||
return withLogging("Page.reload", () -> reloadImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1059,7 +1096,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
options = new ReloadOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonObject json = sendMessage("reload", params, timeoutSettings.navigationTimeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("reload", params).getAsJsonObject();
|
||||
if (json.has("response")) {
|
||||
return connection.getExistingObject(json.getAsJsonObject("response").get("guid").getAsString());
|
||||
}
|
||||
@@ -1068,7 +1105,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void route(String url, Consumer<Route> handler, RouteOptions options) {
|
||||
route(UrlMatcher.forGlob(browserContext.baseUrl(), url, this.connection.localUtils, false), handler, options);
|
||||
route(new UrlMatcher(browserContext.baseUrl, url), handler, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1087,23 +1124,25 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
options = new RouteFromHAROptions();
|
||||
}
|
||||
if (options.update != null && options.update) {
|
||||
browserContext.recordIntoHar(this, har, convertType(options, BrowserContext.RouteFromHAROptions.class), null);
|
||||
browserContext.recordIntoHar(this, har, convertType(options, BrowserContext.RouteFromHAROptions.class));
|
||||
return;
|
||||
}
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(browserContext.baseUrl(), options.url, this.connection.localUtils, false);
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(browserContext.baseUrl, options.url);
|
||||
HARRouter harRouter = new HARRouter(connection.localUtils, har, options.notFound);
|
||||
onClose(context -> harRouter.dispose());
|
||||
route(matcher, route -> harRouter.handle(route), null);
|
||||
}
|
||||
|
||||
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
withLogging("Page.route", () -> {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeWebSocket(String url, Consumer<WebSocketRoute> handler) {
|
||||
routeWebSocketImpl(UrlMatcher.forGlob(browserContext.baseUrl(), url, this.connection.localUtils, true), handler);
|
||||
routeWebSocketImpl(new UrlMatcher(browserContext.baseUrl, url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1117,13 +1156,15 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
private void routeWebSocketImpl(UrlMatcher matcher, Consumer<WebSocketRoute> handler) {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
withLogging("Page.routeWebSocket", () -> {
|
||||
webSocketRoutes.add(matcher, handler);
|
||||
updateWebSocketInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] screenshot(ScreenshotOptions options) {
|
||||
return screenshotImpl(options);
|
||||
return withLogging("Page.screenshot", () -> screenshotImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1140,7 +1181,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
|
||||
return mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class));
|
||||
return withLogging("Page.selectOption",
|
||||
() -> mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1178,7 +1220,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
params.add("mask", maskArray);
|
||||
}
|
||||
JsonObject json = sendMessage("screenshot", params, timeoutSettings.timeout(options.timeout)).getAsJsonObject();
|
||||
JsonObject json = sendMessage("screenshot", params).getAsJsonObject();
|
||||
|
||||
byte[] buffer = Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
if (options.path != null) {
|
||||
@@ -1189,46 +1231,62 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, SelectOption[] values, SelectOptionOptions options) {
|
||||
return mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class));
|
||||
return withLogging("Page.selectOption",
|
||||
() -> mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, ElementHandle[] values, SelectOptionOptions options) {
|
||||
return mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class));
|
||||
return withLogging("Page.selectOption",
|
||||
() -> mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(String selector, boolean checked, SetCheckedOptions options) {
|
||||
mainFrame.setCheckedImpl(selector, checked, convertType(options, Frame.SetCheckedOptions.class));
|
||||
withLogging("Page.setChecked",
|
||||
() -> mainFrame.setCheckedImpl(selector, checked, convertType(options, Frame.SetCheckedOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContent(String html, SetContentOptions options) {
|
||||
mainFrame.setContent(html, convertType(options, Frame.SetContentOptions.class));
|
||||
withLogging("Page.setContent",
|
||||
() -> mainFrame.setContentImpl(html, convertType(options, Frame.SetContentOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultNavigationTimeout(double timeout) {
|
||||
timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
withLogging("Page.setDefaultNavigationTimeout", () -> {
|
||||
timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeout", timeout);
|
||||
sendMessage("setDefaultNavigationTimeoutNoReply", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultTimeout(double timeout) {
|
||||
timeoutSettings.setDefaultTimeout(timeout);
|
||||
withLogging("Page.setDefaultTimeout", () -> {
|
||||
timeoutSettings.setDefaultTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("timeout", timeout);
|
||||
sendMessage("setDefaultTimeoutNoReply", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExtraHTTPHeaders(Map<String, String> headers) {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonArray jsonHeaders = new JsonArray();
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
JsonObject header = new JsonObject();
|
||||
header.addProperty("name", e.getKey());
|
||||
header.addProperty("value", e.getValue());
|
||||
jsonHeaders.add(header);
|
||||
}
|
||||
params.add("headers", jsonHeaders);
|
||||
sendMessage("setExtraHTTPHeaders", params, NO_TIMEOUT);
|
||||
withLogging("Page.setExtraHTTPHeaders", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonArray jsonHeaders = new JsonArray();
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
JsonObject header = new JsonObject();
|
||||
header.addProperty("name", e.getKey());
|
||||
header.addProperty("value", e.getValue());
|
||||
jsonHeaders.add(header);
|
||||
}
|
||||
params.add("headers", jsonHeaders);
|
||||
sendMessage("setExtraHTTPHeaders", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1238,7 +1296,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void setInputFiles(String selector, Path[] files, SetInputFilesOptions options) {
|
||||
mainFrame.setInputFilesImpl(selector, files, convertType(options, Frame.SetInputFilesOptions.class));
|
||||
withLogging("Page.setInputFiles",
|
||||
() -> mainFrame.setInputFilesImpl(selector, files, convertType(options, Frame.SetInputFilesOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1248,30 +1307,35 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void setInputFiles(String selector, FilePayload[] files, SetInputFilesOptions options) {
|
||||
mainFrame.setInputFilesImpl(selector, files, convertType(options, Frame.SetInputFilesOptions.class));
|
||||
withLogging("Page.setInputFiles",
|
||||
() -> mainFrame.setInputFilesImpl(selector, files, convertType(options, Frame.SetInputFilesOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewportSize(int width, int height) {
|
||||
viewport = new ViewportSize(width, height);
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("viewportSize", gson().toJsonTree(viewport));
|
||||
sendMessage("setViewportSize", params, NO_TIMEOUT);
|
||||
withLogging("Page.setViewportSize", () -> {
|
||||
viewport = new ViewportSize(width, height);
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("viewportSize", gson().toJsonTree(viewport));
|
||||
sendMessage("setViewportSize", params);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tap(String selector, TapOptions options) {
|
||||
mainFrame.tap(selector, convertType(options, Frame.TapOptions.class));
|
||||
withLogging("Page.tap",
|
||||
() -> mainFrame.tapImpl(selector, convertType(options, Frame.TapOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String textContent(String selector, TextContentOptions options) {
|
||||
return mainFrame.textContent(selector, convertType(options, Frame.TextContentOptions.class));
|
||||
return withLogging("Page.textContent",
|
||||
() -> mainFrame.textContentImpl(selector, convertType(options, Frame.TextContentOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String title() {
|
||||
return mainFrame.title();
|
||||
return withLogging("Page.title", () -> mainFrame.titleImpl());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1281,23 +1345,27 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void type(String selector, String text, TypeOptions options) {
|
||||
mainFrame.type(selector, text, convertType(options, Frame.TypeOptions.class));
|
||||
withLogging("Page.type",
|
||||
() -> mainFrame.typeImpl(selector, text, convertType(options, Frame.TypeOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncheck(String selector, UncheckOptions options) {
|
||||
mainFrame.uncheck(selector, convertType(options, Frame.UncheckOptions.class));
|
||||
withLogging("Page.uncheck",
|
||||
() -> mainFrame.uncheckImpl(selector, convertType(options, Frame.UncheckOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unrouteAll() {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
withLogging("Page.unrouteAll", () -> {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(UrlMatcher.forGlob(browserContext.baseUrl(), url, this.connection.localUtils, false), handler);
|
||||
unroute(new UrlMatcher(browserContext.baseUrl, url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1311,16 +1379,18 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
withLogging("Page.unroute", () -> {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInterceptionPatterns() {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns(), NO_TIMEOUT);
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
}
|
||||
|
||||
private void updateWebSocketInterceptionPatterns() {
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns(), NO_TIMEOUT);
|
||||
sendMessage("setWebSocketInterceptionPatterns", webSocketRoutes.interceptionPatterns());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1341,7 +1411,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
// Note: we are creating Video object lazily, because we do not know
|
||||
// BrowserContextOptions when constructing the page - it is assigned
|
||||
// too late during launchPersistentContext.
|
||||
if (browserContext.videosDir() == null) {
|
||||
if (browserContext.videosDir == null) {
|
||||
return null;
|
||||
}
|
||||
return forceVideo();
|
||||
@@ -1362,7 +1432,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public JSHandle waitForFunction(String pageFunction, Object arg, WaitForFunctionOptions options) {
|
||||
return mainFrame.waitForFunction(pageFunction, arg, convertType(options, Frame.WaitForFunctionOptions.class));
|
||||
return withLogging("Page.waitForFunction",
|
||||
() -> mainFrame.waitForFunctionImpl(pageFunction, arg, convertType(options, Frame.WaitForFunctionOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1437,7 +1508,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Request waitForRequest(String urlGlob, WaitForRequestOptions options, Runnable code) {
|
||||
return waitForRequest(UrlMatcher.forGlob(browserContext.baseUrl(), urlGlob, this.connection.localUtils, false), null, options, code);
|
||||
return waitForRequest(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1482,7 +1553,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Response waitForResponse(String urlGlob, WaitForResponseOptions options, Runnable code) {
|
||||
return waitForResponse(UrlMatcher.forGlob(browserContext.baseUrl(), urlGlob, this.connection.localUtils, false), null, options, code);
|
||||
return waitForResponse(new UrlMatcher(browserContext.baseUrl, urlGlob), null, options, code);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1515,7 +1586,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public ElementHandle waitForSelector(String selector, WaitForSelectorOptions options) {
|
||||
return mainFrame.waitForSelector(selector, convertType(options, Frame.WaitForSelectorOptions.class));
|
||||
return withLogging("Page.waitForSelector",
|
||||
() -> mainFrame.waitForSelectorImpl(selector, convertType(options, Frame.WaitForSelectorOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1529,12 +1601,12 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void waitForTimeout(double timeout) {
|
||||
mainFrame.waitForTimeout(timeout);
|
||||
withLogging("Page.waitForTimeout", () -> mainFrame.waitForTimeoutImpl(timeout));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(UrlMatcher.forGlob(browserContext.baseUrl(), url, this.connection.localUtils, false), options);
|
||||
waitForURL(new UrlMatcher(browserContext.baseUrl, url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,6 +52,7 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
Connection connection = new Connection(new PipeTransport(p.getInputStream(), p.getOutputStream()), env);
|
||||
PlaywrightImpl result = connection.initializePlaywright();
|
||||
result.driverProcess = p;
|
||||
result.initSharedSelectors(null);
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to launch driver", e);
|
||||
@@ -61,8 +62,9 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
private final BrowserTypeImpl chromium;
|
||||
private final BrowserTypeImpl firefox;
|
||||
private final BrowserTypeImpl webkit;
|
||||
private final SelectorsImpl selectors;
|
||||
private final APIRequestImpl apiRequest;
|
||||
protected SelectorsImpl selectors;
|
||||
private SharedSelectors sharedSelectors;
|
||||
|
||||
PlaywrightImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
@@ -70,20 +72,26 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
firefox = parent.connection.getExistingObject(initializer.getAsJsonObject("firefox").get("guid").getAsString());
|
||||
webkit = parent.connection.getExistingObject(initializer.getAsJsonObject("webkit").get("guid").getAsString());
|
||||
|
||||
chromium.playwright = this;
|
||||
firefox.playwright = this;
|
||||
webkit.playwright = this;
|
||||
|
||||
selectors = new SelectorsImpl();
|
||||
selectors = connection.getExistingObject(initializer.getAsJsonObject("selectors").get("guid").getAsString());
|
||||
apiRequest = new APIRequestImpl(this);
|
||||
}
|
||||
|
||||
public LocalUtils localUtils() {
|
||||
return connection.localUtils;
|
||||
void initSharedSelectors(PlaywrightImpl parent) {
|
||||
assert sharedSelectors == null;
|
||||
if (parent == null) {
|
||||
sharedSelectors = new SharedSelectors();
|
||||
} else {
|
||||
sharedSelectors = parent.sharedSelectors;
|
||||
}
|
||||
sharedSelectors.addChannel(selectors);
|
||||
}
|
||||
|
||||
void unregisterSelectors() {
|
||||
sharedSelectors.removeChannel(selectors);
|
||||
}
|
||||
|
||||
public JsonArray deviceDescriptors() {
|
||||
return localUtils().deviceDescriptors();
|
||||
return connection.localUtils.deviceDescriptors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +116,7 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
|
||||
@Override
|
||||
public Selectors selectors() {
|
||||
return selectors;
|
||||
return sharedSelectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This file is generated by generate_java_rpc.js, do not edit manually.
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import java.util.List;
|
||||
@@ -103,7 +105,6 @@ class ExpectedTextValue {
|
||||
class FrameExpectOptions {
|
||||
Object expressionArg;
|
||||
List<ExpectedTextValue> expectedText;
|
||||
String selector;
|
||||
Double expectedNumber;
|
||||
SerializedArgument expectedValue;
|
||||
Boolean useInnerText;
|
||||
|
||||
@@ -26,4 +26,8 @@ public class RemoteBrowser extends ChannelOwner {
|
||||
BrowserImpl browser() {
|
||||
return connection.getExistingObject(initializer.getAsJsonObject("browser").get("guid").getAsString());
|
||||
}
|
||||
|
||||
SelectorsImpl selectors() {
|
||||
return connection.getExistingObject(initializer.getAsJsonObject("selectors").get("guid").getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
@@ -68,7 +69,7 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
|
||||
@Override
|
||||
public Map<String, String> allHeaders() {
|
||||
return getRawHeaders().headers();
|
||||
return withLogging("Request.allHeaders", () -> getRawHeaders().headers());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,12 +98,12 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
|
||||
@Override
|
||||
public List<HttpHeader> headersArray() {
|
||||
return getRawHeaders().headersArray();
|
||||
return withLogging("Request.headersArray", () -> getRawHeaders().headersArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String headerValue(String name) {
|
||||
return getRawHeaders().get(name);
|
||||
return withLogging("Request.headerValue", () -> getRawHeaders().get(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,21 +153,25 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
|
||||
@Override
|
||||
public ResponseImpl response() {
|
||||
JsonObject result = sendMessage("response").getAsJsonObject();
|
||||
if (!result.has("response")) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(result.getAsJsonObject("response").get("guid").getAsString());
|
||||
return withLogging("Request.response", () -> {
|
||||
JsonObject result = sendMessage("response").getAsJsonObject();
|
||||
if (!result.has("response")) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(result.getAsJsonObject("response").get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sizes sizes() {
|
||||
ResponseImpl response = response();
|
||||
if (response == null) {
|
||||
throw new PlaywrightException("Unable to fetch sizes for failed request");
|
||||
}
|
||||
JsonObject json = response.sendMessage("sizes").getAsJsonObject();
|
||||
return gson().fromJson(json.getAsJsonObject("sizes"), Sizes.class);
|
||||
return withLogging("Request.sizes", () -> {
|
||||
ResponseImpl response = response();
|
||||
if (response == null) {
|
||||
throw new PlaywrightException("Unable to fetch sizes for failed request");
|
||||
}
|
||||
JsonObject json = response.sendMessage("sizes").getAsJsonObject();
|
||||
return gson().fromJson(json.getAsJsonObject("sizes"), Sizes.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -193,8 +198,10 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
if (rawHeaders != null) {
|
||||
return rawHeaders;
|
||||
}
|
||||
JsonObject result = sendMessage("rawRequestHeaders").getAsJsonObject();
|
||||
JsonArray rawHeadersJson = result.getAsJsonArray("headers");
|
||||
JsonArray rawHeadersJson = withLogging("Request.allHeaders", () -> {
|
||||
JsonObject result = sendMessage("rawRequestHeaders").getAsJsonObject();
|
||||
return result.getAsJsonArray("headers");
|
||||
});
|
||||
|
||||
// The field may have been initialized in a nested call but it is ok.
|
||||
rawHeaders = new RawHeaders(asList(gson().fromJson(rawHeadersJson, HttpHeader[].class)));
|
||||
|
||||
@@ -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);
|
||||
@@ -47,13 +48,15 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
|
||||
@Override
|
||||
public Map<String, String> allHeaders() {
|
||||
return getRawHeaders().headers();
|
||||
return withLogging("Response.allHeaders", () -> getRawHeaders().headers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] body() {
|
||||
JsonObject json = sendMessage("body").getAsJsonObject();
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
return withLogging("Response.body", () -> {
|
||||
JsonObject json = sendMessage("body").getAsJsonObject();
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,7 +96,7 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
|
||||
@Override
|
||||
public List<HttpHeader> headersArray() {
|
||||
return getRawHeaders().headersArray();
|
||||
return withLogging("Response.headersArray", () -> getRawHeaders().headersArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,20 +121,24 @@ public class ResponseImpl extends ChannelOwner implements Response {
|
||||
|
||||
@Override
|
||||
public SecurityDetails securityDetails() {
|
||||
JsonObject json = sendMessage("securityDetails").getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return gson().fromJson(json.get("value"), SecurityDetails.class);
|
||||
}
|
||||
return null;
|
||||
return withLogging("Response.securityDetails", () -> {
|
||||
JsonObject json = sendMessage("securityDetails").getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return gson().fromJson(json.get("value"), SecurityDetails.class);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerAddr serverAddr() {
|
||||
JsonObject json = sendMessage("serverAddr").getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return gson().fromJson(json.get("value"), ServerAddr.class);
|
||||
}
|
||||
return null;
|
||||
return withLogging("Response.serverAddr", () -> {
|
||||
JsonObject json = sendMessage("serverAddr").getAsJsonObject();
|
||||
if (json.has("value")) {
|
||||
return gson().fromJson(json.get("value"), ServerAddr.class);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,15 +38,18 @@ 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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(String errorCode) {
|
||||
startHandling();
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("errorCode", errorCode);
|
||||
sendMessageAsync("abort", params);
|
||||
withLogging("Route.abort", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("errorCode", errorCode);
|
||||
sendMessageAsync("abort", params);
|
||||
});
|
||||
}
|
||||
|
||||
boolean isHandled() {
|
||||
@@ -61,7 +64,7 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
void resume(ResumeOptions options, boolean isFallback) {
|
||||
startHandling();
|
||||
applyOverrides(convertType(options, FallbackOptions.class));
|
||||
resumeImpl(request().fallbackOverridesForResume(), isFallback);
|
||||
withLogging("Route.resume", () -> resumeImpl(request().fallbackOverridesForResume(), isFallback));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,7 +152,7 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
@Override
|
||||
public void fulfill(FulfillOptions options) {
|
||||
startHandling();
|
||||
fulfillImpl(options);
|
||||
withLogging("Route.fulfill", () -> fulfillImpl(options));
|
||||
}
|
||||
|
||||
private void fulfillImpl(FulfillOptions options) {
|
||||
|
||||
@@ -17,72 +17,28 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Selectors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class SelectorsImpl extends LoggingSupport implements Selectors {
|
||||
protected final List<BrowserContextImpl> contextsForSelectors = new ArrayList<>();
|
||||
protected final List<JsonObject> selectorEngines = new ArrayList<>();
|
||||
|
||||
String testIdAttributeName = "data-testid";
|
||||
|
||||
@Override
|
||||
public void setTestIdAttribute(String attributeName) {
|
||||
if (attributeName == null) {
|
||||
throw new PlaywrightException("Test id attribute cannot be null");
|
||||
}
|
||||
testIdAttributeName = attributeName;
|
||||
for (BrowserContextImpl context : contextsForSelectors) {
|
||||
try {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("testIdAttributeName", attributeName);
|
||||
context.sendMessageAsync("setTestIdAttributeName", params);
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
}
|
||||
class SelectorsImpl extends ChannelOwner {
|
||||
SelectorsImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String name, String script, RegisterOptions options) {
|
||||
registerImpl(name, script, options);
|
||||
void register(String name, String script, Selectors.RegisterOptions options) {
|
||||
if (options == null) {
|
||||
options = new Selectors.RegisterOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("name", name);
|
||||
params.addProperty("source", script);
|
||||
sendMessage("register", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String name, Path path, RegisterOptions options) {
|
||||
byte[] buffer;
|
||||
try {
|
||||
buffer = Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read selector from file: " + path, e);
|
||||
}
|
||||
registerImpl(name, new String(buffer, UTF_8), options);
|
||||
}
|
||||
|
||||
private void registerImpl(String name, String script, RegisterOptions options) {
|
||||
if (selectorEngines.stream().anyMatch(engine -> name.equals(engine.get("name").getAsString()))) {
|
||||
throw new PlaywrightException("selectors.register: \"" + name + "\" selector engine has been already registered");
|
||||
}
|
||||
|
||||
JsonObject engine = new JsonObject();
|
||||
engine.addProperty("name", name);
|
||||
engine.addProperty("source", script);
|
||||
if (options != null && options.contentScript != null) {
|
||||
engine.addProperty("contentScript", options.contentScript);
|
||||
}
|
||||
for (BrowserContextImpl context : contextsForSelectors) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("selectorEngine", engine);
|
||||
context.sendMessage("registerSelectorEngine", params, NO_TIMEOUT);
|
||||
}
|
||||
selectorEngines.add(engine);
|
||||
void setTestIdAttributeName(String name) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("testIdAttributeName", name);
|
||||
sendMessageAsync("setTestIdAttributeName", params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Selectors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class SharedSelectors extends LoggingSupport implements Selectors {
|
||||
private final List<SelectorsImpl> channels = new ArrayList<>();
|
||||
private final List<Registration> registrations = new ArrayList<>();
|
||||
|
||||
String testIdAttributeName = "data-testid";
|
||||
|
||||
private static class Registration {
|
||||
final String name;
|
||||
final String script;
|
||||
final RegisterOptions options;
|
||||
|
||||
Registration(String name, String script, RegisterOptions options) {
|
||||
this.name = name;
|
||||
this.script = script;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String name, String script, RegisterOptions options) {
|
||||
withLogging("Selectors.register", () -> registerImpl(name, script, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String name, Path path, RegisterOptions options) {
|
||||
withLogging("Selectors.register", () -> {
|
||||
byte[] buffer;
|
||||
try {
|
||||
buffer = Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read selector from file: " + path, e);
|
||||
}
|
||||
registerImpl(name, new String(buffer, UTF_8), options);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTestIdAttribute(String attributeName) {
|
||||
if (attributeName == null) {
|
||||
throw new PlaywrightException("Test id attribute cannot be null");
|
||||
}
|
||||
testIdAttributeName = attributeName;
|
||||
channels.forEach(channel -> channel.setTestIdAttributeName(testIdAttributeName));
|
||||
}
|
||||
|
||||
void addChannel(SelectorsImpl channel) {
|
||||
registrations.forEach(r -> {
|
||||
try {
|
||||
channel.register(r.name, r.script, r.options);
|
||||
} catch (PlaywrightException e) {
|
||||
// This should not fail except for connection closure, but just in case we catch.
|
||||
}
|
||||
channel.setTestIdAttributeName(testIdAttributeName);
|
||||
});
|
||||
channels.add(channel);
|
||||
}
|
||||
|
||||
void removeChannel(SelectorsImpl channel) {
|
||||
channels.remove(channel);
|
||||
}
|
||||
|
||||
private void registerImpl(String name, String script, RegisterOptions options) {
|
||||
channels.forEach(impl -> impl.register(name, script, options));
|
||||
registrations.add(new Registration(name, script, options));
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class Stream extends ChannelOwner {
|
||||
}
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("size", len);
|
||||
JsonObject json = sendMessage("read", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("read", params).getAsJsonObject();
|
||||
String encoded = json.get("binary").getAsString();
|
||||
if (encoded.isEmpty()) {
|
||||
return -1;
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
class TimeoutSettings {
|
||||
private static final int DEFAULT_TIMEOUT_MS = 30_000;
|
||||
private static final int DEFAULT_LAUNCH_TIMEOUT_MS = 180_000;
|
||||
|
||||
private final TimeoutSettings parent;
|
||||
private Double defaultTimeout ;
|
||||
@@ -81,11 +80,4 @@ class TimeoutSettings {
|
||||
}
|
||||
return new WaitableTimeout<>(timeout(timeout));
|
||||
}
|
||||
|
||||
static double launchTimeout(Double timeout) {
|
||||
if (timeout != null) {
|
||||
return timeout;
|
||||
}
|
||||
return DEFAULT_LAUNCH_TIMEOUT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Touchscreen;
|
||||
|
||||
import static com.microsoft.playwright.impl.ChannelOwner.NO_TIMEOUT;
|
||||
|
||||
class TouchscreenImpl implements Touchscreen {
|
||||
private final PageImpl page;
|
||||
|
||||
@@ -30,9 +28,11 @@ class TouchscreenImpl implements Touchscreen {
|
||||
|
||||
@Override
|
||||
public void tap(double x, double y) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("x", x);
|
||||
params.addProperty("y", y);
|
||||
page.sendMessage("touchscreenTap", params, NO_TIMEOUT);
|
||||
page.withLogging("Touchscreen.tap", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("x", x);
|
||||
params.addProperty("y", y);
|
||||
page.sendMessage("touchscreenTap", params);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -45,7 +46,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
// Not interested in artifacts.
|
||||
if (path == null) {
|
||||
params.addProperty("mode", "discard");
|
||||
sendMessage("tracingStopChunk", params, NO_TIMEOUT);
|
||||
sendMessage("tracingStopChunk", params);
|
||||
if (stacksId != null) {
|
||||
connection.localUtils().traceDiscarded(stacksId);
|
||||
}
|
||||
@@ -55,14 +56,14 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
boolean isLocal = !connection.isRemote;
|
||||
if (isLocal) {
|
||||
params.addProperty("mode", "entries");
|
||||
JsonObject json = sendMessage("tracingStopChunk", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
|
||||
JsonArray entries = json.getAsJsonArray("entries");
|
||||
connection.localUtils.zip(path, entries, stacksId, false, includeSources);
|
||||
return;
|
||||
}
|
||||
|
||||
params.addProperty("mode", "archive");
|
||||
JsonObject json = sendMessage("tracingStopChunk", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
|
||||
// The artifact may be missing if the browser closed while stopping tracing.
|
||||
if (!json.has("artifact")) {
|
||||
if (stacksId != null) {
|
||||
@@ -87,7 +88,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
|
||||
@Override
|
||||
public void group(String name, GroupOptions options) {
|
||||
groupImpl(name, options);
|
||||
withLogging("Tracing.group", () -> groupImpl(name, options));
|
||||
}
|
||||
|
||||
private void groupImpl(String name, GroupOptions options) {
|
||||
@@ -96,12 +97,12 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("name", name);
|
||||
sendMessage("tracingGroup", params, NO_TIMEOUT);
|
||||
sendMessage("tracingGroup", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void groupEnd() {
|
||||
sendMessage("tracingGroupEnd");
|
||||
withLogging("Tracing.groupEnd", () -> sendMessage("tracingGroupEnd"));
|
||||
}
|
||||
|
||||
private void tracingStartChunk(String name, String title) {
|
||||
@@ -112,7 +113,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
if (title != null) {
|
||||
params.addProperty("title", title);
|
||||
}
|
||||
JsonObject result = sendMessage("tracingStartChunk", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonObject result = sendMessage("tracingStartChunk", params).getAsJsonObject();
|
||||
startCollectingStacks(result.get("traceName").getAsString());
|
||||
}
|
||||
|
||||
@@ -134,7 +135,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
if (includeSources) {
|
||||
params.addProperty("sources", true);
|
||||
}
|
||||
sendMessage("tracingStart", params, NO_TIMEOUT);
|
||||
sendMessage("tracingStart", params);
|
||||
tracingStartChunk(options.name, options.title);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,22 +21,25 @@ import com.microsoft.playwright.PlaywrightException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
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 {
|
||||
private final String baseURL;
|
||||
public final String glob;
|
||||
public final Pattern pattern;
|
||||
public final Predicate<String> predicate;
|
||||
|
||||
static UrlMatcher forOneOf(URL baseUrl, Object object, LocalUtils localUtils, boolean isWebSocketUrl) {
|
||||
static UrlMatcher forOneOf(URL baseUrl, Object object) {
|
||||
if (object == null) {
|
||||
return new UrlMatcher(null, null, null);
|
||||
return new UrlMatcher(null, null, null, null);
|
||||
}
|
||||
if (object instanceof String) {
|
||||
return UrlMatcher.forGlob(baseUrl, (String) object, localUtils, isWebSocketUrl);
|
||||
return new UrlMatcher(baseUrl, (String) object);
|
||||
}
|
||||
if (object instanceof Pattern) {
|
||||
return new UrlMatcher((Pattern) object);
|
||||
@@ -63,32 +66,61 @@ class UrlMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
private static String normaliseUrl(String spec) {
|
||||
try {
|
||||
// Align with the Node.js URL parser which automatically adds a slash to the path if it is empty.
|
||||
URI url = new URI(spec);
|
||||
if (url.getScheme() != null &&
|
||||
Arrays.asList("http", "https", "ws", "wss").contains(url.getScheme()) &&
|
||||
url.getPath().isEmpty()) {
|
||||
return new URI(url.getScheme(), url.getAuthority(), "/", url.getQuery(), url.getFragment()).toString();
|
||||
}
|
||||
return url.toString();
|
||||
} catch (URISyntaxException e) {
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
UrlMatcher(URL baseURL, String glob) {
|
||||
this(baseURL, glob, null, null);
|
||||
}
|
||||
|
||||
UrlMatcher(Pattern pattern) {
|
||||
this(null, pattern, null);
|
||||
this(null, null, pattern, null);
|
||||
}
|
||||
|
||||
UrlMatcher(Predicate<String> predicate) {
|
||||
this(null, null, predicate);
|
||||
this(null, null, null, predicate);
|
||||
}
|
||||
|
||||
private UrlMatcher(String glob, Pattern pattern, Predicate<String> predicate) {
|
||||
private UrlMatcher(URL baseURL, String glob, Pattern pattern, Predicate<String> predicate) {
|
||||
this.baseURL = baseURL != null ? baseURL.toString() : null;
|
||||
this.glob = glob;
|
||||
this.pattern = pattern;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
boolean test(String value) {
|
||||
return testImpl(baseURL, pattern, predicate, glob, value);
|
||||
}
|
||||
|
||||
private static boolean testImpl(String baseURL, Pattern pattern, Predicate<String> predicate, String glob, String value) {
|
||||
if (pattern != null) {
|
||||
return pattern.matcher(value).find();
|
||||
}
|
||||
if (predicate != null) {
|
||||
return predicate.test(value);
|
||||
}
|
||||
if (glob != null) {
|
||||
if (!glob.startsWith("*")) {
|
||||
// Allow http(s) baseURL to match ws(s) urls.
|
||||
if (baseURL != null && Pattern.compile("^https?://").matcher(baseURL).find() && Pattern.compile("^wss?://").matcher(value).find()) {
|
||||
baseURL = baseURL.replaceFirst("^http", "ws");
|
||||
}
|
||||
glob = normaliseUrl(resolveUrl(baseURL, glob));
|
||||
}
|
||||
return Pattern.compile(globToRegex(glob)).matcher(value).find();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -125,12 +157,10 @@ class UrlMatcher {
|
||||
|
||||
@Override
|
||||
public String 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>";
|
||||
return String.format("<glob pattern=\"%s\">", glob);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.ClientCertificate;
|
||||
@@ -31,11 +32,11 @@ 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.ChannelOwner.NO_TIMEOUT;
|
||||
import static com.microsoft.playwright.impl.Serialization.toJsonArray;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
|
||||
@@ -90,6 +91,79 @@ 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 {
|
||||
@@ -201,7 +275,7 @@ public class Utils {
|
||||
items.add(item);
|
||||
}
|
||||
tempFilesParams.add("items", items);
|
||||
return context.sendMessage("createTempFiles", tempFilesParams, NO_TIMEOUT).getAsJsonObject();
|
||||
return context.sendMessage("createTempFiles", tempFilesParams).getAsJsonObject();
|
||||
}
|
||||
|
||||
static void checkFilePayloadSize(FilePayload[] files) {
|
||||
|
||||
@@ -30,6 +30,7 @@ class VideoImpl implements Video {
|
||||
|
||||
VideoImpl(PageImpl page) {
|
||||
this.page = page;
|
||||
BrowserImpl browser = page.context().browser();
|
||||
}
|
||||
|
||||
void setArtifact(ArtifactImpl artifact) {
|
||||
@@ -43,33 +44,39 @@ class VideoImpl implements Video {
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
try {
|
||||
waitForArtifact().delete();
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
page.withLogging("Video.delete", () -> {
|
||||
try {
|
||||
waitForArtifact().delete();
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path path() {
|
||||
if (page.connection.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use saveAs() to save a local copy.");
|
||||
}
|
||||
try {
|
||||
return Paths.get(waitForArtifact().initializer.get("absolutePath").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
return page.withLogging("Video.path", () -> {
|
||||
if (page.connection.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use saveAs() to save a local copy.");
|
||||
}
|
||||
try {
|
||||
return Paths.get(waitForArtifact().initializer.get("absolutePath").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Path path) {
|
||||
if (!page.isClosed()) {
|
||||
throw new PlaywrightException("Page is not yet closed. Close the page prior to calling saveAs");
|
||||
}
|
||||
try {
|
||||
waitForArtifact().saveAs(path);
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
page.withLogging("Video.saveAs", () -> {
|
||||
if (!page.isClosed()) {
|
||||
throw new PlaywrightException("Page is not yet closed. Close the page prior to calling saveAs");
|
||||
}
|
||||
try {
|
||||
waitForArtifact().saveAs(path);
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,21 +38,23 @@ public class WaitForEventLogger<T> implements Supplier<T>, Logger {
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
{
|
||||
return channel.withLogging(apiName, () -> {
|
||||
{
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("phase", "before");
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("phase", "before");
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("phase", "after");
|
||||
try {
|
||||
return supplier.apply(this);
|
||||
} catch (RuntimeException e) {
|
||||
info.addProperty("error", e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
info.addProperty("phase", "after");
|
||||
try {
|
||||
return supplier.apply(this);
|
||||
} catch (RuntimeException e) {
|
||||
info.addProperty("error", e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,6 +69,7 @@ class WebSocketRouteImpl extends ChannelOwner implements WebSocketRoute {
|
||||
|
||||
WebSocketRouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
markAsInternalType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,11 +129,7 @@ class WebSocketRouteImpl extends ChannelOwner implements WebSocketRoute {
|
||||
return;
|
||||
}
|
||||
// Ensure that websocket is "open" and can send messages without an actual server connection.
|
||||
try {
|
||||
sendMessageAsync("ensureOpened");
|
||||
} catch (PlaywrightException e) {
|
||||
// If this happens after the page has been closed, ignore the error.
|
||||
}
|
||||
sendMessageAsync("ensureOpened");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,21 +71,25 @@ class WorkerImpl extends ChannelOwner implements Worker {
|
||||
|
||||
@Override
|
||||
public Object evaluate(String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpression", params, NO_TIMEOUT);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return withLogging("Worker.evaluate", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpression", params);
|
||||
SerializedValue value = gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle evaluateHandle(String pageFunction, Object arg) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params, NO_TIMEOUT);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString());
|
||||
return withLogging("Worker.evaluateHandle", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", pageFunction);
|
||||
params.add("arg", gson().toJsonTree(serializeArgument(arg)));
|
||||
JsonElement json = sendMessage("evaluateExpressionHandle", params);
|
||||
return connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("handle").get("guid").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,7 +42,7 @@ class WritableStream extends ChannelOwner {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(b, off, len);
|
||||
ByteBuffer encoded = Base64.getEncoder().encode(buffer);
|
||||
params.addProperty("binary", new String(encoded.array(), StandardCharsets.UTF_8));
|
||||
sendMessage("write", params, NO_TIMEOUT);
|
||||
sendMessage("write", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,12 +48,6 @@ public class Cookie {
|
||||
* Optional.
|
||||
*/
|
||||
public SameSiteAttribute sameSite;
|
||||
/**
|
||||
* For partitioned third-party cookies (aka <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
|
||||
* partition key. Optional.
|
||||
*/
|
||||
public String partitionKey;
|
||||
|
||||
public Cookie(String name, String value) {
|
||||
this.name = name;
|
||||
@@ -109,13 +103,4 @@ public class Cookie {
|
||||
this.sameSite = sameSite;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* For partitioned third-party cookies (aka <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies">CHIPS</a>), the
|
||||
* partition key. Optional.
|
||||
*/
|
||||
public Cookie setPartitionKey(String partitionKey) {
|
||||
this.partitionKey = partitionKey;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -218,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 || exchange.getRequestMethod().equals("HEAD")) ? -1 : contentLength);
|
||||
exchange.sendResponseHeaders(200, contentLength == 0 ? -1 : contentLength);
|
||||
if (contentLength > 0) {
|
||||
exchange.getResponseBody().write(body.toByteArray());
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ public class TestBrowserContextCredentials extends TestBase {
|
||||
@Test
|
||||
@DisabledIf(value="isChromiumHeadedLike", disabledReason="fail")
|
||||
void shouldFailWithoutCredentials() {
|
||||
System.out.println("channel2 " + getBrowserChannelFromEnv());
|
||||
server.setAuth("/empty.html", "user", "pass");
|
||||
Response response = page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals(401, response.status());
|
||||
|
||||
@@ -436,7 +436,7 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
|
||||
context.request().get(server.PREFIX + "/slow", RequestOptions.create().setTimeout(100));
|
||||
});
|
||||
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -468,7 +468,7 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
|
||||
context.setDefaultTimeout(100);
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.request().get(server.PREFIX + "/redirect"));
|
||||
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.HarContentPolicy;
|
||||
import com.microsoft.playwright.options.HarMode;
|
||||
import com.microsoft.playwright.options.HarNotFound;
|
||||
import com.microsoft.playwright.options.RouteFromHarUpdateContentPolicy;
|
||||
@@ -39,6 +40,7 @@ import static com.microsoft.playwright.Utils.copy;
|
||||
import static com.microsoft.playwright.Utils.extractZip;
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static com.microsoft.playwright.options.HarContentPolicy.ATTACH;
|
||||
import static com.microsoft.playwright.options.HarContentPolicy.EMBED;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestBrowserContextHar extends TestBase {
|
||||
|
||||
+8
-21
@@ -174,19 +174,10 @@ public class TestBrowserContextStorageState extends TestBase {
|
||||
@Test
|
||||
void shouldSupportIndexedDB() {
|
||||
page.navigate(server.PREFIX + "/to-do-notifications/index.html");
|
||||
|
||||
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
|
||||
" - list:\n" +
|
||||
" - listitem: Database initialised."
|
||||
);
|
||||
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();
|
||||
assertThat(page.locator("#notifications")).matchesAriaSnapshot(
|
||||
" - list:\n" +
|
||||
" - listitem: \"Transaction completed: database modification finished.\""
|
||||
);
|
||||
|
||||
String storageState = page.context().storageState(new BrowserContext.StorageStateOptions().setIndexedDB(true));
|
||||
assertJsonEquals("{\"cookies\":[],\"origins\":[\n" +
|
||||
@@ -204,18 +195,14 @@ public class TestBrowserContextStorageState extends TestBase {
|
||||
" \"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" +
|
||||
" \"value\": {\n" +
|
||||
" \"day\": \"01\",\n" +
|
||||
" \"hours\": \"1\",\n" +
|
||||
" \"minutes\": \"1\",\n" +
|
||||
" \"month\": \"January\",\n" +
|
||||
" \"notified\": \"no\",\n" +
|
||||
" \"taskTitle\": \"Pet the cat\",\n" +
|
||||
" \"year\": \"2025\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
|
||||
@@ -57,35 +57,18 @@ public class TestChromiumTracing extends TestBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static void rafraf(Page page) {
|
||||
int count = 2;
|
||||
for (int i = 0; i < count; i++) {
|
||||
page.evaluate("() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOException {
|
||||
try (Page page = browser.newPage()) {
|
||||
Path outputTraceFile = tempDir.resolve("trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setPath(outputTraceFile)
|
||||
.setCategories(asList("disabled-by-default-cc.debug")));
|
||||
rafraf(page);
|
||||
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
|
||||
browser.stopTracing();
|
||||
try (FileReader fileReader = new FileReader(outputTraceFile.toFile())) {
|
||||
JsonObject traceJson = new Gson().fromJson(fileReader, JsonObject.class);
|
||||
// NOTE: trace-config is deprecated as per http://crrev.com/c/6628182
|
||||
boolean hasTraceConfig =
|
||||
traceJson.getAsJsonObject("metadata").get("trace-config") != null
|
||||
&& traceJson.getAsJsonObject("metadata").get("trace-config").getAsString().contains("disabled-by-default-cc.debug");
|
||||
boolean hasTraceEvents = traceJson.getAsJsonArray("traceEvents").asList().stream()
|
||||
.anyMatch(event -> {
|
||||
JsonObject eventObj = (JsonObject) event;
|
||||
return eventObj.has("cat") &&
|
||||
eventObj.get("cat").getAsString().equals("disabled-by-default-cc.debug");
|
||||
});
|
||||
assertTrue(hasTraceConfig || hasTraceEvents);
|
||||
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
|
||||
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ public class TestClientCertificates extends TestBase {
|
||||
.setIgnoreHTTPSErrors(true) // TODO: remove once we can pass a custom CA.
|
||||
.setClientCertificates(asList(
|
||||
new ClientCertificate(customServer.origin)
|
||||
.setPfxPath(asset("client-certificates/client/trusted/keystore.p12"))
|
||||
.setPassphrase("")));
|
||||
.setPfxPath(asset("client-certificates/client/trusted/client_keystore.p12"))
|
||||
.setPassphrase("passphrase")));
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(requestOptions);
|
||||
APIResponse response = request.get(customServer.url);
|
||||
|
||||
@@ -307,19 +307,4 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
assertTrue(Files.list(userDataDir).count() > 0);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExposeBrowser() {
|
||||
Page page = launchPersistent();
|
||||
BrowserContext context = page.context();
|
||||
Browser browser = context.browser();
|
||||
assertFalse(browser.version().isEmpty());
|
||||
Page page2 = browser.newPage();
|
||||
page2.navigate("data:text/html,<html><title>Title</title></html>");
|
||||
assertEquals("Title", page2.title());
|
||||
browser.close();
|
||||
assertEquals(0, context.pages().size());
|
||||
// Next line should not throw.
|
||||
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()) {
|
||||
if (isFirefox() || isWebKit()) {
|
||||
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()) {
|
||||
if (isFirefox() || isWebKit()) {
|
||||
assertEquals(0, input.evaluate("el => el.selectionStart"));
|
||||
assertEquals(10, input.evaluate("el => el.selectionEnd"));
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.microsoft.playwright.APIRequest.NewContextOptions;
|
||||
import com.microsoft.playwright.options.HttpCredentials;
|
||||
import com.microsoft.playwright.options.HttpCredentialsSend;
|
||||
import com.microsoft.playwright.options.HttpHeader;
|
||||
@@ -38,8 +37,6 @@ import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestGlobalFetch extends TestBase {
|
||||
private static final List<String> HTTP_METHODS = asList("GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH");
|
||||
|
||||
@Test
|
||||
void shouldHaveJavaInDefaultUesrAgent() throws ExecutionException, InterruptedException {
|
||||
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions());
|
||||
@@ -189,7 +186,7 @@ public class TestGlobalFetch extends TestBase {
|
||||
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
|
||||
server.setRoute("/empty.html", exchange -> {});
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
|
||||
assertTrue(e.getMessage().contains("Timeout 100ms exceeded"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +337,7 @@ public class TestGlobalFetch extends TestBase {
|
||||
for (String method : new String[] {"head", "put", "trace"}) {
|
||||
server.setRoute("/empty.html", exchange -> {
|
||||
exchange.getResponseHeaders().set("Content-type", "text/plain");
|
||||
exchange.sendResponseHeaders(404, exchange.getRequestMethod().equals("HEAD") ? -1 : 10);
|
||||
exchange.sendResponseHeaders(404, 10);
|
||||
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("Not found.");
|
||||
}
|
||||
@@ -361,7 +358,7 @@ public class TestGlobalFetch extends TestBase {
|
||||
server.setRedirect("/b/c/redirect4", "/simple.json");
|
||||
|
||||
APIRequestContext request = playwright.request().newContext();
|
||||
for (String method : HTTP_METHODS) {
|
||||
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
|
||||
for (int maxRedirects = 1; maxRedirects < 4; maxRedirects++) {
|
||||
int currMaxRedirects = maxRedirects;
|
||||
PlaywrightException exception = assertThrows(PlaywrightException.class,
|
||||
@@ -373,69 +370,13 @@ public class TestGlobalFetch extends TestBase {
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseMaxRedirectsFromFetchWhenProvidedOverridingNewContext() {
|
||||
server.setRedirect("/a/redirect1", "/b/c/redirect2");
|
||||
server.setRedirect("/b/c/redirect2", "/b/c/redirect3");
|
||||
server.setRedirect("/b/c/redirect3", "/b/c/redirect4");
|
||||
server.setRedirect("/b/c/redirect4", "/simple.json");
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(new NewContextOptions().setMaxRedirects(1));
|
||||
for (String method : HTTP_METHODS) {
|
||||
APIResponse response = request.fetch(server.PREFIX + "/a/redirect1",
|
||||
RequestOptions.create().setMethod(method).setMaxRedirects(4));
|
||||
assertEquals(200, response.status());
|
||||
}
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFollowRedirectsUpToMaxRedirectsLimitSetInNewContext() {
|
||||
server.setRedirect("/a/redirect1", "/b/c/redirect2");
|
||||
server.setRedirect("/b/c/redirect2", "/b/c/redirect3");
|
||||
server.setRedirect("/b/c/redirect3", "/b/c/redirect4");
|
||||
server.setRedirect("/b/c/redirect4", "/simple.json");
|
||||
|
||||
for (String method : HTTP_METHODS) {
|
||||
for (int maxRedirects = 1; maxRedirects <= 4; maxRedirects++) {
|
||||
int currMaxRedirects = maxRedirects;
|
||||
APIRequestContext request = playwright.request().newContext(new NewContextOptions().setMaxRedirects(currMaxRedirects));
|
||||
if (maxRedirects < 4) {
|
||||
PlaywrightException exception = assertThrows(PlaywrightException.class,
|
||||
() -> request.fetch(server.PREFIX + "/a/redirect1",
|
||||
RequestOptions.create().setMethod(method)));
|
||||
assertTrue(exception.getMessage().contains("Max redirect count exceeded"), exception.getMessage());
|
||||
} else {
|
||||
APIResponse response = request.fetch(server.PREFIX + "/a/redirect1", RequestOptions.create().setMethod(method));
|
||||
assertEquals(200, response.status());
|
||||
}
|
||||
request.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0InNewContext() {
|
||||
server.setRedirect("/a/redirect1", "/b/c/redirect2");
|
||||
server.setRedirect("/b/c/redirect2", "/simple.json");
|
||||
|
||||
APIRequestContext request = playwright.request().newContext(new NewContextOptions().setMaxRedirects(0));
|
||||
for (String method : HTTP_METHODS) {
|
||||
APIResponse response = request.fetch(server.PREFIX + "/a/redirect1",
|
||||
RequestOptions.create().setMethod(method));
|
||||
assertEquals("/b/c/redirect2", response.headers().get("location"));
|
||||
assertEquals(302, response.status());
|
||||
}
|
||||
request.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0() {
|
||||
server.setRedirect("/a/redirect1", "/b/c/redirect2");
|
||||
server.setRedirect("/b/c/redirect2", "/simple.json");
|
||||
|
||||
APIRequestContext request = playwright.request().newContext();
|
||||
for (String method : HTTP_METHODS) {
|
||||
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
|
||||
APIResponse response = request.fetch(server.PREFIX + "/a/redirect1",
|
||||
RequestOptions.create().setMethod(method).setMaxRedirects(0));
|
||||
assertEquals("/b/c/redirect2", response.headers().get("location"));
|
||||
@@ -450,7 +391,7 @@ public class TestGlobalFetch extends TestBase {
|
||||
server.setRedirect("/b/c/redirect2", "/simple.json");
|
||||
|
||||
APIRequestContext request = playwright.request().newContext();
|
||||
for (String method : HTTP_METHODS) {
|
||||
for (String method : new String[] {"GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"}) {
|
||||
PlaywrightException exception = assertThrows(PlaywrightException.class,
|
||||
() -> request.fetch(server.PREFIX + "/a/redirect1",
|
||||
RequestOptions.create().setMethod(method).setMaxRedirects(-1)));
|
||||
|
||||
@@ -18,12 +18,10 @@ package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.assertions.LocatorAssertions;
|
||||
import com.microsoft.playwright.assertions.PlaywrightAssertions;
|
||||
import com.microsoft.playwright.assertions.LocatorAssertions.ContainsClassOptions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
import org.opentest4j.ValueWrapper;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
@@ -1070,7 +1068,7 @@ public class TestLocatorAssertions extends TestBase {
|
||||
Locator locator = page.locator("div");
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(1000);
|
||||
AssertionFailedError exception = assertThrows(AssertionFailedError.class, () -> assertThat(locator).hasText("foo"));
|
||||
assertTrue(exception.getMessage().contains("Assert \"hasText\" with timeout 1000ms"), exception.getMessage());
|
||||
assertTrue(exception.getMessage().contains("Locator.expect with timeout 1000ms"), exception.getMessage());
|
||||
// Restore default.
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(5_000);
|
||||
}
|
||||
@@ -1094,49 +1092,4 @@ public class TestLocatorAssertions extends TestBase {
|
||||
// Restore default.
|
||||
PlaywrightAssertions.setDefaultAssertionTimeout(5_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsClassPass() {
|
||||
page.setContent("<div class='foo bar baz'></div>");
|
||||
Locator locator = page.locator("div");
|
||||
assertThat(locator).containsClass("");
|
||||
assertThat(locator).containsClass("bar");
|
||||
assertThat(locator).containsClass("baz bar");
|
||||
assertThat(locator).containsClass(" bar foo ");
|
||||
assertThat(locator).not().containsClass(" baz not-matching");
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsClassPassWithSvgs() {
|
||||
page.setContent("<svg class='c1 c2' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'></svg>");
|
||||
assertThat(page.locator("svg")).containsClass("c1");
|
||||
assertThat(page.locator("svg")).containsClass("c2 c1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsClassFail() {
|
||||
page.setContent("<div class='bar baz'></div>");
|
||||
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
|
||||
assertThat(page.locator("div")).containsClass("does-not-exist", new ContainsClassOptions().setTimeout(1000));
|
||||
});
|
||||
assertTrue(e.getMessage().contains("Assert \"containsClass\" with timeout 1000ms"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsClassPassWithArray() {
|
||||
page.setContent("<div class='foo'></div><div class='hello bar'></div><div class='baz'></div>");
|
||||
Locator locator = page.locator("div");
|
||||
assertThat(locator).containsClass(asList("foo", "hello", "baz"));
|
||||
assertThat(locator).not().hasClass(new String[]{"not-there", "hello", "baz"}); // Class not there
|
||||
assertThat(locator).not().hasClass(new String[]{"foo", "hello"}); // length mismatch
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsClassFailWithArray() {
|
||||
page.setContent("<div class='foo'></div><div class='bar'></div><div class='bar'></div>");
|
||||
AssertionFailedError e = assertThrows(AssertionFailedError.class, () -> {
|
||||
assertThat(page.locator("div")).containsClass(asList("foo", "bar", "baz"), new ContainsClassOptions().setTimeout(1000));
|
||||
});
|
||||
assertTrue(e.getMessage().contains("Assert \"containsClass\" with timeout 1000ms"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +218,6 @@ public class TestLocatorAssertions2 extends TestBase {
|
||||
AssertionFailedError e = assertThrows(AssertionFailedError.class, () ->
|
||||
assertThat(locator).isChecked(new LocatorAssertions.IsCheckedOptions().setIndeterminate(true).setTimeout(1000)));
|
||||
// TODO: should be "assertThat().isChecked() with timeout 1000ms"
|
||||
assertTrue(e.getMessage().contains("Assert \"isChecked\" with timeout 1000ms"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Locator.expect with timeout 1000ms"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ public class TestPageAddLocatorHandler extends TestBase {
|
||||
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.locator("#target").click(new Locator.ClickOptions().setTimeout(3_000)));
|
||||
assertEquals(0, (int) page.evaluate("window.clicked"));
|
||||
assertTrue(page.locator("#interstitial").isVisible());
|
||||
assertThat(page.locator("#interstitial")).isVisible();
|
||||
assertEquals(1, called[0]);
|
||||
assertTrue(e.getMessage().contains("locator handler has finished, waiting for getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(\"close\")) to be hidden"), e.getMessage());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.microsoft.playwright;
|
||||
import com.microsoft.playwright.junit.FixtureTest;
|
||||
import com.microsoft.playwright.junit.UsePlaywright;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -13,7 +12,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@FixtureTest
|
||||
@UsePlaywright
|
||||
@@ -69,7 +67,7 @@ public class TestPageAriaSnapshot {
|
||||
@Test
|
||||
void shouldSnapshotComplex(Page page) {
|
||||
page.setContent("<ul><li><a href='about:blank'>link</a></li></ul>");
|
||||
checkAndMatchSnapshot(page.locator("body"), "- list:\n - listitem:\n - link \"link\":\n - /url: about:blank");
|
||||
checkAndMatchSnapshot(page.locator("body"), "- list:\n - listitem:\n - link \"link\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -85,46 +83,4 @@ public class TestPageAriaSnapshot {
|
||||
page.setContent("<details><summary>Summary</summary><div>Details</div></details>");
|
||||
checkAndMatchSnapshot(page.locator("body"), "- group: Summary");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSnapshotChildren(Page page) {
|
||||
page.setContent("<ul><li><img />One</li><li>Two</li><li>Three</li></ul>");
|
||||
assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: equal\n - listitem\n - listitem: Two\n - listitem: Three");
|
||||
assertThat(page.locator("body")).not().matchesAriaSnapshot("- list:\n - /children: equal\n - listitem\n - listitem: Two");
|
||||
|
||||
assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - img\n - text: One\n - listitem: Two\n - listitem: Three");
|
||||
assertThat(page.locator("body")).not().matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - text: One\n - listitem: Two\n - listitem: Three");
|
||||
assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - /children: contain\n - text: One\n - listitem: Two\n - listitem: Three");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMatchUrl(Page page) {
|
||||
page.setContent("<a href='https://example.com'>Link</a>");
|
||||
assertThat(page.locator("body")).matchesAriaSnapshot("" +
|
||||
"- link:\n" +
|
||||
" - /url: /.*example.com/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleTopLevelDeepEqual(Page page) {
|
||||
// https://github.com/microsoft/playwright/issues/36456
|
||||
page.setContent("" +
|
||||
"<ul>\n" +
|
||||
" <li>\n" +
|
||||
" <ul>\n" +
|
||||
" <li>1.1</li>\n" +
|
||||
" <li>1.2</li>\n" +
|
||||
" </ul>\n" +
|
||||
" </li>\n" +
|
||||
"</ul>");
|
||||
|
||||
assertThrows(AssertionFailedError.class, () -> {
|
||||
assertThat(page.locator("body")).matchesAriaSnapshot("" +
|
||||
"- /children: deep-equal\n" +
|
||||
"- list:\n" +
|
||||
" - listitem:\n" +
|
||||
" - listitem: \"1.1\"\n" +
|
||||
" - listitem: \"1.2\"");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,8 +391,8 @@ public class TestPageClock {
|
||||
page.clock().install(new Clock.InstallOptions().setTime(0));
|
||||
page.navigate("data:text/html,");
|
||||
page.clock().pauseAt(1000);
|
||||
// Internally wait to make sure the clock is paused and not running.
|
||||
page.waitForTimeout(1111);
|
||||
page.waitForTimeout(1000);
|
||||
page.clock().resume();
|
||||
int now = (int) page.evaluate("() => Date.now()");
|
||||
assertTrue(now >= 0 && now <= 1000);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import static com.microsoft.playwright.options.ColorScheme.LIGHT;
|
||||
import static com.microsoft.playwright.options.Media.PRINT;
|
||||
import static com.microsoft.playwright.Utils.attachFrame;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestPageEmulateMedia extends TestBase {
|
||||
@Test
|
||||
|
||||
@@ -18,12 +18,11 @@ package com.microsoft.playwright;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.microsoft.playwright.impl.PlaywrightImpl;
|
||||
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -99,7 +98,7 @@ public class TestPageInterception extends TestBase {
|
||||
page.route("**/*", route -> {
|
||||
PlaywrightException error = assertThrows(PlaywrightException.class,
|
||||
() -> route.fetch(new Route.FetchOptions().setTimeout(1000)));
|
||||
assertTrue(error.getMessage().contains("Timeout 1000ms exceeded"), error.getMessage());
|
||||
assertTrue(error.getMessage().contains("Request timed out after 1000ms"), error.getMessage());
|
||||
});
|
||||
PlaywrightException error = assertThrows(PlaywrightException.class,
|
||||
() -> page.navigate(server.PREFIX + "/slow", new Page.NavigateOptions().setTimeout(2000)));
|
||||
@@ -142,91 +141,13 @@ public class TestPageInterception extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithGlob() {
|
||||
assertTrue(globToRegex("**/*.js").matcher("https://localhost:8080/foo.js").find());
|
||||
assertFalse(globToRegex("**/*.css").matcher("https://localhost:8080/foo.js").find());
|
||||
assertFalse(globToRegex("*.js").matcher("https://localhost:8080/foo.js").find());
|
||||
assertTrue(globToRegex("https://**/*.js").matcher("https://localhost:8080/foo.js").find());
|
||||
assertTrue(globToRegex("http://localhost:8080/simple/path.js").matcher("http://localhost:8080/simple/path.js").find());
|
||||
assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/a.js").find());
|
||||
assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/b.js").find());
|
||||
assertFalse(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/c.js").find());
|
||||
|
||||
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpg").find());
|
||||
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpeg").find());
|
||||
assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.png").find());
|
||||
assertFalse(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.css").find());
|
||||
assertTrue(globToRegex("foo*").matcher("foo.js").find());
|
||||
assertFalse(globToRegex("foo*").matcher("foo/bar.js").find());
|
||||
assertFalse(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidc/foo").find());
|
||||
assertTrue(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidcnice").find());
|
||||
|
||||
// range [] is NOT supported
|
||||
assertTrue(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/v[0-9]").find());
|
||||
assertFalse(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/version").find());
|
||||
|
||||
// query params
|
||||
assertTrue(globToRegex("**/api\\?param").matcher("http://example.com/api?param").find());
|
||||
assertFalse(globToRegex("**/api\\?param").matcher("http://example.com/api-param").find());
|
||||
assertTrue(globToRegex("**/three-columns/settings.html\\?**id=settings-**").matcher("http://mydomain:8080/blah/blah/three-columns/settings.html?id=settings-e3c58efe-02e9-44b0-97ac-dd138100cf7c&blah").find());
|
||||
|
||||
assertEquals("^\\?$", globToRegex("\\?").pattern());
|
||||
assertEquals("^\\\\$", globToRegex("\\").pattern());
|
||||
assertEquals("^\\\\$", globToRegex("\\\\").pattern());
|
||||
assertEquals("^\\[$", globToRegex("\\[").pattern());
|
||||
assertEquals("^\\[a-z\\]$", globToRegex("[a-z]").pattern());
|
||||
assertEquals("^\\$\\^\\+\\.\\*\\(\\)\\|\\?\\{\\}\\[\\]$", globToRegex("$^+.\\*()|\\?\\{\\}\\[\\]").pattern());
|
||||
|
||||
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/", "http://playwright.dev"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/?a=b", "http://playwright.dev?a=b"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/", "h*://playwright.dev"));
|
||||
assertTrue(urlMatches(null, "http://api.playwright.dev/?x=y", "http://*.playwright.dev?x=y"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/foo/bar", "**/foo/**"));
|
||||
assertTrue(urlMatches("http://playwright.dev", "http://playwright.dev/?x=y", "?x=y"));
|
||||
assertTrue(urlMatches("http://playwright.dev/foo/", "http://playwright.dev/foo/bar?x=y", "./bar?x=y"));
|
||||
|
||||
// This is not supported, we treat ? as a query separator.
|
||||
assertFalse(urlMatches(null, "http://localhost:8080/Simple/path.js", "http://localhost:8080/?imple/path.js"));
|
||||
assertFalse(urlMatches(null, "http://playwright.dev/", "http://playwright.?ev"));
|
||||
assertTrue(urlMatches(null, "http://playwright./?ev", "http://playwright.?ev"));
|
||||
assertFalse(urlMatches(null, "http://playwright.dev/foo", "http://playwright.dev/f??"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/f??", "http://playwright.dev/f??"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev\\\\?x=y"));
|
||||
assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev/\\\\?x=y"));
|
||||
assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "?bar"));
|
||||
assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "\\\\?bar"));
|
||||
assertTrue(urlMatches("http://first.host/", "http://second.host/foo", "**/foo"));
|
||||
assertTrue(urlMatches("http://playwright.dev/", "http://localhost/", "*//localhost/"));
|
||||
|
||||
String[] customPrefixes = {"about", "data", "chrome", "edge", "file"};
|
||||
for (String prefix : customPrefixes) {
|
||||
assertTrue(urlMatches("http://playwright.dev/", prefix + ":blank", prefix + ":blank"));
|
||||
assertFalse(urlMatches("http://playwright.dev/", prefix + ":blank", "http://playwright.dev/"));
|
||||
assertTrue(urlMatches(null, prefix + ":blank", prefix + ":blank"));
|
||||
assertTrue(urlMatches(null, prefix + ":blank", prefix + ":*"));
|
||||
assertFalse(urlMatches(null, "not" + prefix + ":blank", prefix + ":*"));
|
||||
}
|
||||
}
|
||||
|
||||
Pattern globToRegex(String glob) {
|
||||
return globToRegex(glob, null, false);
|
||||
}
|
||||
|
||||
Pattern globToRegex(String glob, String baseURL, boolean webSocketUrl) {
|
||||
return ((PlaywrightImpl) playwright).localUtils().globToRegex(glob, baseURL, webSocketUrl);
|
||||
}
|
||||
|
||||
boolean urlMatches(String baseURL, String urlString, String match) {
|
||||
if (match == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String glob = (String) match;
|
||||
if (glob.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return globToRegex(glob, baseURL, false).matcher(urlString).find();
|
||||
void shouldProperlyHandleCharacterSetsInGlobs() {
|
||||
page.route("**/[a-z]*.html", route -> {
|
||||
APIResponse response = route.fetch(new Route.FetchOptions().setUrl(server.PREFIX + "/one-style.html"));
|
||||
route.fulfill(new Route.FulfillOptions().setResponse(response));
|
||||
});
|
||||
Response response = page.navigate(server.PREFIX + "/empty.html");
|
||||
assertEquals(200, response.status());
|
||||
assertTrue(response.text().contains("one-style.css"), response.text());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.HttpHeader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -80,83 +77,4 @@ public class TestPageRequestContinue extends TestBase {
|
||||
e.getMessage().contains("frame was detached"), e.getMessage());
|
||||
assertTrue(done[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value = "com.microsoft.playwright.TestBase#isFirefox", disabledReason = "We currently clear all headers during interception in firefox")
|
||||
void continueShouldNotPropagateCookieOverrideToRedirects() throws ExecutionException, InterruptedException {
|
||||
// https://github.com/microsoft/playwright/issues/35168
|
||||
server.setRoute("/set-cookie", exchange -> {
|
||||
exchange.getResponseHeaders().add("Set-Cookie", "foo=bar;");
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
exchange.getResponseBody().close();
|
||||
});
|
||||
page.navigate(server.PREFIX + "/set-cookie");
|
||||
assertEquals("foo=bar", page.evaluate("() => document.cookie"));
|
||||
|
||||
server.setRedirect("/redirect", server.PREFIX + "/empty.html");
|
||||
page.route("**/redirect", route -> {
|
||||
Map<String, String> headers = new HashMap<>(route.request().allHeaders());
|
||||
headers.put("cookie", "override");
|
||||
route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
});
|
||||
|
||||
Future<Server.Request> serverRequest = server.futureRequest("/empty.html");
|
||||
page.navigate(server.PREFIX + "/redirect");
|
||||
assertEquals(asList("foo=bar"), serverRequest.get().headers.get("cookie"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value = "com.microsoft.playwright.TestBase#isFirefox", disabledReason = "We currently clear all headers during interception in firefox")
|
||||
void continueShouldNotOverrideCookie() throws ExecutionException, InterruptedException {
|
||||
// https://github.com/microsoft/playwright/issues/35168
|
||||
server.setRoute("/set-cookie", exchange -> {
|
||||
exchange.getResponseHeaders().add("Set-Cookie", "foo=bar;");
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
exchange.getResponseBody().close();
|
||||
});
|
||||
page.navigate(server.PREFIX + "/set-cookie");
|
||||
assertEquals("foo=bar", page.evaluate("() => document.cookie"));
|
||||
|
||||
page.route("**", route -> {
|
||||
Map<String, String> headers = new HashMap<>(route.request().allHeaders());
|
||||
headers.put("cookie", "override");
|
||||
headers.put("custom", "value");
|
||||
route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
});
|
||||
|
||||
Future<Server.Request> serverRequest = server.futureRequest("/empty.html");
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
|
||||
// Original cookie from the browser's cookie jar should be sent.
|
||||
assertEquals(asList("foo=bar"), serverRequest.get().headers.get("cookie"));
|
||||
assertEquals(asList("value"), serverRequest.get().headers.get("custom"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void redirectAfterContinueShouldBeAbleToDeleteCookie() throws ExecutionException, InterruptedException {
|
||||
// https://github.com/microsoft/playwright/issues/35168
|
||||
server.setRoute("/set-cookie", exchange -> {
|
||||
exchange.getResponseHeaders().add("Set-Cookie", "foo=bar;");
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
exchange.getResponseBody().close();
|
||||
});
|
||||
page.navigate(server.PREFIX + "/set-cookie");
|
||||
assertEquals("foo=bar", page.evaluate("() => document.cookie"));
|
||||
|
||||
server.setRoute("/delete-cookie", exchange -> {
|
||||
exchange.getResponseHeaders().add("Set-Cookie", "foo=bar; expires=Thu, 01 Jan 1970 00:00:00 GMT");
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
exchange.getResponseBody().close();
|
||||
});
|
||||
server.setRedirect("/redirect", "/delete-cookie");
|
||||
page.route("**/redirect", route -> {
|
||||
// Pass original headers explicitly when continuing.
|
||||
route.resume(new Route.ResumeOptions().setHeaders(route.request().allHeaders()));
|
||||
});
|
||||
page.navigate(server.PREFIX + "/redirect");
|
||||
|
||||
Future<Server.Request> serverRequest = server.futureRequest("/empty.html");
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertNull(serverRequest.get().headers.get("cookie"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import com.microsoft.playwright.options.Cookie;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
|
||||
@@ -110,7 +110,7 @@ public class TestPageRoute extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSupportQuestionMarkInGlobPattern() {
|
||||
void shouldSupportQuestionMarkInGlobPattern() {
|
||||
server.setRoute("/index", exchange -> {
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
@@ -123,18 +123,6 @@ public class TestPageRoute extends TestBase {
|
||||
writer.write("index123hello");
|
||||
}
|
||||
});
|
||||
server.setRoute("/index?hello", exchange -> {
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("index?hello");
|
||||
}
|
||||
});
|
||||
server.setRoute("/index1hello", exchange -> {
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("index1hello");
|
||||
}
|
||||
});
|
||||
|
||||
page.route("**/index?hello", route -> {
|
||||
route.fulfill(new Route.FulfillOptions().setBody("intercepted any character"));
|
||||
@@ -151,8 +139,7 @@ public class TestPageRoute extends TestBase {
|
||||
assertTrue(page.content().contains("index-no-hello"), page.content());
|
||||
|
||||
page.navigate(server.PREFIX + "/index1hello");
|
||||
assertFalse(page.content().contains("intercepted any character"), page.content());
|
||||
assertTrue(page.content().contains("index1hello"), page.content());
|
||||
assertTrue(page.content().contains("intercepted any character"), page.content());
|
||||
|
||||
page.navigate(server.PREFIX + "/index123hello");
|
||||
assertTrue(page.content().contains("index123hello"), page.content());
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.List;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
|
||||
public class TestPageSelectOption extends TestBase {
|
||||
@Test
|
||||
@@ -239,64 +238,4 @@ public class TestPageSelectOption extends TestBase {
|
||||
assertEquals(asList("blue"), page.evaluate("() => window['result'].onChange"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWaitForOptionToBeEnabled() {
|
||||
page.setContent(
|
||||
"<select disabled>\n" +
|
||||
" <option>one</option>\n" +
|
||||
" <option>two</option>\n" +
|
||||
"</select>\n" +
|
||||
"\n" +
|
||||
"<script>\n" +
|
||||
"function hydrate() {\n" +
|
||||
" const select = document.querySelector('select');\n" +
|
||||
" select.removeAttribute('disabled');\n" +
|
||||
" select.addEventListener('change', () => {\n" +
|
||||
" window['result'] = select.value;\n" +
|
||||
" });\n" +
|
||||
"}\n" +
|
||||
"</script>");
|
||||
|
||||
page.evaluate("() => setTimeout(hydrate, 1000)");
|
||||
page.locator("select").selectOption("two");
|
||||
|
||||
assertEquals("two", page.evaluate("window['result']"));
|
||||
assertThat(page.locator("select")).hasValue("two");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWaitForSelectToBeSwapped() {
|
||||
page.setContent(
|
||||
"<select disabled>\n" +
|
||||
" <option>one</option>\n" +
|
||||
" <option>two</option>\n" +
|
||||
"</select>\n" +
|
||||
"\n" +
|
||||
"<script>\n" +
|
||||
"function hydrate() {\n" +
|
||||
" const select = document.querySelector('select');\n" +
|
||||
" select.remove();\n" +
|
||||
"\n" +
|
||||
" const newSelect = document.createElement('select');\n" +
|
||||
" const option1 = document.createElement('option');\n" +
|
||||
" option1.textContent = 'one';\n" +
|
||||
" newSelect.appendChild(option1);\n" +
|
||||
" const option2 = document.createElement('option');\n" +
|
||||
" option2.textContent = 'two';\n" +
|
||||
" newSelect.appendChild(option2);\n" +
|
||||
"\n" +
|
||||
" document.body.appendChild(newSelect);\n" +
|
||||
"\n" +
|
||||
" newSelect.addEventListener('change', () => {\n" +
|
||||
" window['result'] = newSelect.value;\n" +
|
||||
" });\n" +
|
||||
"}\n" +
|
||||
"</script>");
|
||||
|
||||
page.evaluate("() => setTimeout(window.hydrate, 1000)");
|
||||
page.locator("select").selectOption("two");
|
||||
|
||||
assertThat(page.locator("select")).hasValue("two");
|
||||
assertEquals("two", page.evaluate("window['result']"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
}
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> input.click());
|
||||
fileChooser.setFiles(uploadFiles.toArray(new Path[0]));
|
||||
Object filesLen = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Choose File")).evaluate("e => e.files.length");
|
||||
Object filesLen = page.getByRole(AriaRole.TEXTBOX).evaluate("e => e.files.length");
|
||||
assertTrue(fileChooser.isMultiple());
|
||||
assertEquals(filesCount, filesLen);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,13 @@ public class TestPdf extends TestBase {
|
||||
assertTrue(outlineSize > noOutlineSize, "Unexpected sizes: " + outlineSize + " noOutline: " + noOutlineSize);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip")
|
||||
void shouldThrowInNonChromium() {
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.pdf());
|
||||
assertTrue(e.getMessage().contains("PDF generation is only supported for Headless Chromium"), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="skip")
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.PlaywrightImpl;
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -23,26 +23,25 @@ import java.nio.file.Paths;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestSelectorsRegister extends TestBase {
|
||||
private static final String TAG_SELECTOR_SCRIPT = "{\n" +
|
||||
" create(root, target) {\n" +
|
||||
" return target.nodeName;\n" +
|
||||
" },\n" +
|
||||
" query(root, selector) {\n" +
|
||||
" return root.querySelector(selector);\n" +
|
||||
" },\n" +
|
||||
" queryAll(root, selector) {\n" +
|
||||
" return Array.from(root.querySelectorAll(selector));\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
@Test
|
||||
void shouldWork() {
|
||||
String selectorScript = "{\n" +
|
||||
" create(root, target) {\n" +
|
||||
" return target.nodeName;\n" +
|
||||
" },\n" +
|
||||
" query(root, selector) {\n" +
|
||||
" return root.querySelector(selector);\n" +
|
||||
" },\n" +
|
||||
" queryAll(root, selector) {\n" +
|
||||
" return Array.from(root.querySelectorAll(selector));\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
// Register one engine before creating context.
|
||||
playwright.selectors().register("tag", TAG_SELECTOR_SCRIPT);
|
||||
playwright.selectors().register("tag", selectorScript);
|
||||
|
||||
BrowserContext context = browser.newContext();
|
||||
// Register another engine after creating context.
|
||||
playwright.selectors().register("tag2", TAG_SELECTOR_SCRIPT);
|
||||
playwright.selectors().register("tag2", selectorScript);
|
||||
|
||||
Page page = context.newPage();
|
||||
page.setContent("<div><span></span></div><div></div>");
|
||||
@@ -135,21 +134,4 @@ public class TestSelectorsRegister extends TestBase {
|
||||
});
|
||||
assertTrue(e.getMessage().contains("\"css\" is a predefined selector engine"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAlreadyRegisteredErrorWhenRegistering() {
|
||||
// https://github.com/microsoft/playwright/issues/36467
|
||||
|
||||
// this test is about the exception *before* there's a context created
|
||||
context.close();
|
||||
|
||||
// Register the selector engine first
|
||||
playwright.selectors().register("alreadyRegistered", TAG_SELECTOR_SCRIPT);
|
||||
|
||||
// Attempt to register the same selector engine again should throw an error
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
|
||||
playwright.selectors().register("alreadyRegistered", TAG_SELECTOR_SCRIPT);
|
||||
});
|
||||
assertTrue(e.getMessage().contains("\"alreadyRegistered\" selector engine has been already registered"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -242,66 +241,6 @@ public class TestSelectorsRole extends TestBase {
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setDisabled(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInheritDisabledFromTheAncestor() {
|
||||
page.setContent(
|
||||
"<span aria-disabled=\"true\">\n" +
|
||||
" <button>Click me!</button>\n" +
|
||||
"</span>");
|
||||
assertThat(page.locator("button")).isDisabled();
|
||||
|
||||
page.setContent(
|
||||
"<span aria-disabled=\"true\">\n" +
|
||||
" <h1>Heading</h1>\n" +
|
||||
"</span>");
|
||||
// Non-control roles do not inherit disabled state
|
||||
assertThat(page.locator("h1")).isEnabled();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportDisabledFieldset() {
|
||||
page.setContent(
|
||||
"<fieldset disabled>\n" +
|
||||
" <input></input>\n" +
|
||||
" <button data-testid=\"inside-fieldset-element\">x</button>\n" +
|
||||
" <legend>\n" +
|
||||
" <button data-testid=\"inside-legend-element\">legend</button>\n" +
|
||||
" </legend>\n" +
|
||||
"</fieldset>\n" +
|
||||
"\n" +
|
||||
"<fieldset disabled>\n" +
|
||||
" <legend>\n" +
|
||||
" <div>\n" +
|
||||
" <button data-testid=\"nested-inside-legend-element\">x</button>\n" +
|
||||
" </div>\n" +
|
||||
" </legend>\n" +
|
||||
"</fieldset>\n" +
|
||||
"\n" +
|
||||
"<fieldset disabled>\n" +
|
||||
" <div></div>\n" +
|
||||
" <legend>\n" +
|
||||
" <button data-testid=\"first-legend-element\">x</button>\n" +
|
||||
" </legend>\n" +
|
||||
" <legend>\n" +
|
||||
" <button data-testid=\"second-legend-element\">x</button>\n" +
|
||||
" </legend>\n" +
|
||||
"</fieldset>\n" +
|
||||
"\n" +
|
||||
"<fieldset disabled>\n" +
|
||||
" <fieldset>\n" +
|
||||
" <button data-testid=\"deep-button\">x</button>\n" +
|
||||
" </fieldset>\n" +
|
||||
"</fieldset>");
|
||||
|
||||
assertThat(page.getByTestId("inside-legend-element")).isEnabled();
|
||||
assertThat(page.getByTestId("nested-inside-legend-element")).isEnabled();
|
||||
assertThat(page.getByTestId("first-legend-element")).isEnabled();
|
||||
// Only the first legend is exempt from disabled fieldset
|
||||
assertThat(page.getByTestId("second-legend-element")).isDisabled();
|
||||
// Nested fieldsets inherit disabled state
|
||||
assertThat(page.getByTestId("deep-button")).isDisabled();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportLevel() {
|
||||
page.setContent("<h1>Hello</h1>\n" +
|
||||
@@ -418,6 +357,15 @@ public class TestSelectorsRole extends TestBase {
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("^H[ae]llo$"))).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.locator("role=button[name=/h.*o/i]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("h.*o", Pattern.CASE_INSENSITIVE))).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import com.microsoft.playwright.options.Location;
|
||||
import com.microsoft.playwright.options.MouseButton;
|
||||
@@ -182,7 +182,7 @@ public class TestTracing extends TestBase {
|
||||
List<TraceEvent> events = parseTraceEvents(traceFile1);
|
||||
List<TraceEvent> groups = events.stream().filter(e -> "tracingGroup".equals(e.method)).collect(Collectors.toList());
|
||||
assertEquals(1, groups.size());
|
||||
assertEquals("actual", groups.get(0).title);
|
||||
assertEquals("actual", groups.get(0).apiName);
|
||||
|
||||
}
|
||||
|
||||
@@ -203,8 +203,8 @@ public class TestTracing extends TestBase {
|
||||
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
|
||||
|
||||
List<TraceEvent> events = parseTraceEvents(traceFile1);
|
||||
List<String> calls = events.stream().filter(e -> e.renderedTitle() != null).map(e -> e.renderedTitle()).collect(Collectors.toList());
|
||||
assertEquals(asList("outer group", "Frame.goto", "inner group 1", "Frame.click", "inner group 2", "Frame.isVisible"), calls);
|
||||
List<String> calls = events.stream().filter(e -> e.apiName != null).map(e -> e.apiName).collect(Collectors.toList());
|
||||
assertEquals(asList("outer group", "Page.navigate", "inner group 1", "Frame.click", "inner group 2", "Page.isVisible"), calls);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -241,30 +241,30 @@ public class TestTracing extends TestBase {
|
||||
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
|
||||
|
||||
List<TraceEvent> events = parseTraceEvents(traceFile1);
|
||||
List<String> calls = events.stream().filter(e -> e.renderedTitle() != null).map(e -> e.renderedTitle())
|
||||
List<String> calls = events.stream().filter(e -> e.apiName != null).map(e -> e.apiName)
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(asList(
|
||||
"BrowserContext.clockInstall",
|
||||
"Frame.setContent",
|
||||
"Clock.install",
|
||||
"Page.setContent",
|
||||
"Frame.click",
|
||||
"Frame.click",
|
||||
"Page.keyboardType",
|
||||
"Page.keyboardPress",
|
||||
"Page.keyboardDown",
|
||||
"Page.keyboardInsertText",
|
||||
"Page.keyboardUp",
|
||||
"Page.mouseMove",
|
||||
"Page.mouseDown",
|
||||
"Page.mouseMove",
|
||||
"Page.mouseWheel",
|
||||
"Page.mouseUp",
|
||||
"BrowserContext.clockFastForward",
|
||||
"BrowserContext.clockFastForward",
|
||||
"BrowserContext.clockPauseAt",
|
||||
"BrowserContext.clockRunFor",
|
||||
"BrowserContext.clockSetFixedTime",
|
||||
"BrowserContext.clockSetSystemTime",
|
||||
"BrowserContext.clockResume",
|
||||
"Keyboard.type",
|
||||
"Keyboard.press",
|
||||
"Keyboard.down",
|
||||
"Keyboard.insertText",
|
||||
"Keyboard.up",
|
||||
"Mouse.move",
|
||||
"Mouse.down",
|
||||
"Mouse.move",
|
||||
"Mouse.wheel",
|
||||
"Mouse.up",
|
||||
"Clock.fastForward",
|
||||
"Clock.fastForward",
|
||||
"Clock.pauseAt",
|
||||
"Clock.runFor",
|
||||
"Clock.setFixedTime",
|
||||
"Clock.setSystemTime",
|
||||
"Clock.resume",
|
||||
"Frame.click"),
|
||||
calls);
|
||||
}
|
||||
@@ -285,31 +285,19 @@ public class TestTracing extends TestBase {
|
||||
context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1));
|
||||
|
||||
List<TraceEvent> events = parseTraceEvents(traceFile1);
|
||||
List<String> calls = events.stream().filter(e -> e.renderedTitle() != null).map(e -> e.renderedTitle())
|
||||
List<String> calls = events.stream().filter(e -> e.apiName != null).map(e -> e.apiName)
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(asList("Frame.goto"), calls);
|
||||
assertEquals(asList("Page.navigate"), calls);
|
||||
}
|
||||
|
||||
private static class TraceEvent {
|
||||
String type;
|
||||
String name;
|
||||
String title;
|
||||
@SerializedName("class")
|
||||
String clazz;
|
||||
String apiName;
|
||||
String method;
|
||||
Double startTime;
|
||||
Double endTime;
|
||||
String callId;
|
||||
|
||||
String renderedTitle() {
|
||||
if (title != null) {
|
||||
return title;
|
||||
}
|
||||
if (clazz != null && method != null) {
|
||||
return clazz + "." + method;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TraceEvent> parseTraceEvents(Path traceFile) throws IOException {
|
||||
|
||||
@@ -1,16 +1,66 @@
|
||||
# Client Certificate test-certificates
|
||||
|
||||
Regenerate all certificates by running:
|
||||
## Server
|
||||
|
||||
```bash
|
||||
openssl req \
|
||||
-x509 \
|
||||
-newkey rsa:4096 \
|
||||
-keyout server/server_key.pem \
|
||||
-out server/server_cert.pem \
|
||||
-nodes \
|
||||
-days 365 \
|
||||
-subj "/CN=localhost/O=Client\ Certificate\ Demo" \
|
||||
-addext "subjectAltName=DNS:localhost,DNS:local.playwright"
|
||||
```
|
||||
|
||||
## Trusted client-certificate (server signed/valid)
|
||||
|
||||
```
|
||||
bash generate.sh
|
||||
mkdir -p client/trusted
|
||||
# generate server-signed (valid) certifcate
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-keyout client/trusted/key.pem \
|
||||
-out client/trusted/csr.pem \
|
||||
-nodes \
|
||||
-days 365 \
|
||||
-subj "/CN=Alice"
|
||||
|
||||
# sign with server_cert.pem
|
||||
openssl x509 \
|
||||
-req \
|
||||
-in client/trusted/csr.pem \
|
||||
-CA server/server_cert.pem \
|
||||
-CAkey server/server_key.pem \
|
||||
-out client/trusted/cert.pem \
|
||||
-set_serial 01 \
|
||||
-days 365
|
||||
```
|
||||
|
||||
## Self-signed certificate (invalid)
|
||||
|
||||
```
|
||||
mkdir -p client/self-signed
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-keyout client/self-signed/key.pem \
|
||||
-out client/self-signed/csr.pem \
|
||||
-nodes \
|
||||
-days 365 \
|
||||
-subj "/CN=Bob"
|
||||
|
||||
# sign with self-signed/key.pem
|
||||
openssl x509 \
|
||||
-req \
|
||||
-in client/self-signed/csr.pem \
|
||||
-signkey client/self-signed/key.pem \
|
||||
-out client/self-signed/cert.pem \
|
||||
-days 365
|
||||
```
|
||||
|
||||
## Java: Convert PEM Files to PKCS12
|
||||
|
||||
|
||||
Java server understands only PKCS12 keys, after copying the certificates from Node.js Playwright we need to convert them.
|
||||
|
||||
```
|
||||
bash generate_java.sh
|
||||
openssl pkcs12 -export -in server_cert.pem -inkey server_key.pem -out server_keystore.p12 -name myalias
|
||||
```
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEyzCCArOgAwIBAgIUUo60oaPj20QM6oeGSn+2CT5j7GYwDQYJKoZIhvcNAQEL
|
||||
BQAwDjEMMAoGA1UEAwwDQm9iMB4XDTI1MDcyMTE1NTYyMFoXDTM1MDcxOTE1NTYy
|
||||
MIIEyzCCArOgAwIBAgIUYps4gh4MqFYg8zqQhHYL7zYfbLkwDQYJKoZIhvcNAQEL
|
||||
BQAwDjEMMAoGA1UEAwwDQm9iMB4XDTI0MDcxOTEyNDc0MFoXDTI1MDcxOTEyNDc0
|
||||
MFowDjEMMAoGA1UEAwwDQm9iMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
|
||||
AgEAzQMXYOZz3ILrbF9qpDng2pw2wJf1UFopehwaYyu7riWJ9+ADrhSnCSFBM3Sc
|
||||
MBc/8dIR6etWwci8QwJ/MtvIU0yx4llq+53G+19Bc1teC6q/b4QCRDIcTGxOZoR+
|
||||
jfYZVjPODEyJ5y5MZIo34ZP4bu+JnpT4W7+uojm3jOoyNPqXMcc70uAhfSKG+Jfr
|
||||
wZKteA4T5VKFytVcWgh4v03z8zTYeW3kD4lCsongBz6yu2dn3D6XMROnxiPwi+IR
|
||||
QqX1pwnJ0UA3CTeOHEw1jA3koxWIIg44PWaPaCj9Udrhf4ew00XLPWVZP8T5rVf8
|
||||
yUfecWQCR7FueJFqoLhPMMFi17rYmGZUvw3/YkXBjay4Q9e+G2WS3Xk8u+I1sCuV
|
||||
BJNBRv9DqtMC9D/N9NI8GkLrXwZmk82SXG+cQ0TSkNUHYI/03YKoqsn5H8PsG7Tc
|
||||
+Y2Ca6TaCWims7lvOg7U0E6lu2h5NGcdWHFPJ9qfe+xho/yfYYwGqEKanGAu1kd5
|
||||
SbIaX6/YiM5/Pp/96MeRNrB9kLzDnZTNuGtdCawVFgbkWmfX2Z6/a0d6SvZGDzBx
|
||||
xTVZRB0my01E1FP53MS8YRH98HUjGEwNRVq2e1W+aXldKppgZ85GZD3l2YTeuI0i
|
||||
PJCDUzQiaWzFtWc8s13YQ1HLCOyOXF7QqMyNCiLGb4xQ56kCAwEAAaMhMB8wHQYD
|
||||
VR0OBBYEFMqdCDxkZm8HxNI4MLLveAVTdH7UMA0GCSqGSIb3DQEBCwUAA4ICAQAB
|
||||
MKd3WEJ8zI51FuyeTcMq6L1zk2vmKTFg6T7HZJhNZoD1AYvvsKJ8mrqeSwhxqjlE
|
||||
0H2FGLY+Z8Fw3+TE1QuvTuz3gwRI+yzBEyqi/fEGCGrhOVcWaXGgLCtWG+BA4Su8
|
||||
HenK97/n3OnXUnBozRPZMH02IaLrOiEGbpaabXKCCabpm5U1oGq437e3SeAeIL7U
|
||||
WxuHhHBx0yo9j7ACaCL6mz8xpk8NaRZpPy22MTlrPKwbOK2eYf3Jy5fHa/f6edTs
|
||||
KqZewI7t4oe/OqKdjyTgGYkjTE3Xcmo2T/fmcAeEP3HJX267kCzBi5J3McwonWxD
|
||||
N8zz9qKSf5YGQy140eEOTjjESwlPz6zfrTW92YdCIr63k9UCDL2HGQTRSxB6g4BQ
|
||||
loVzKS9/BKhulGqvSGvEoj6D+qG/PgFlBtJoE71X+vSIxvdbnOVmOi/l+NGNuP1Z
|
||||
nwnDtZWp4BKshhSKvqeOI+EyNMQ4FL20S4w8T+LR873jKrbd2MEuAsJiygWh+/ZJ
|
||||
haHTEhFxvH/a4i8gb/SGZlFB6oyPJ+XM5kZo4fcp7PnzxhYrIaEpPq+AR/3657hm
|
||||
AajXpS5lTCkNJc85QeHHj/0geDsOvfK4XUj2lgaJ0gXpgsoxnSCSq6Xox6ZqAVON
|
||||
0ra1KkGBTQH+5DxJ2Gp1UBaucrLYZTfXuJ8fPYeeNQ==
|
||||
AgEA179eTsqcc1c3AOQHzCZEyYLPta2CCAscUFqcEZ9vWvjW0uzOv9TDlB33Unov
|
||||
jch4CElZOBhzTadVsbmnYKpxwyVU89WCuQKvedz4k1vu7S1YryfNbmS8PWbnQ4ds
|
||||
9NB7SgJNHZILvx9DXuWeFEyzRIo1984z4HheBzrkf791LqpYKaKziANUo8h8t0dm
|
||||
TX/boOz8cEnQNwtTC0ZX3aD0obG/UAhr/22ZGPo/E659fh4ptyYX2LrIUHGy+Eux
|
||||
nJ9Y4cTqa88Ee6K6AkDiT/AoNQNxE4X++jqLuie8j/ZYpI1Oll38GwKVOyy1msRL
|
||||
toGmISNwkMIQDGABrJlxgpP4QQAQ+08v9srzXOlkdxdr7OCP81r+ccBXiSQEe7BA
|
||||
kdJ8l98l5dprJ++GJ+SZcV4+/iGR0dKU2IdAG5HiKZIFn6ch9Ux+UMqeGaYCpkHr
|
||||
TiietHwcXgtVBlE0jFmB/HspmI/O0abK+grMmueaH7XtTI8YHnw0mUpL8+yp7mfA
|
||||
7zFusgFgyiBPXeD/NQgg8vja67k++d1VGoXm2xr+5WPQCSbgQoMkkOBMLHWJTefd
|
||||
6F4Z5M+oI0VwYbf6eQW246wJgpCHSPR0Vdijd6MAGRWKUuLfDsA9+12iGbKvwJ2e
|
||||
nJlStft2V2LZcjBfdIMbigW1aSVNN5w6m6YVrQPry3WPkWcCAwEAAaMhMB8wHQYD
|
||||
VR0OBBYEFPxKWTFQJSg4HD2qjxL0dnXX/z4qMA0GCSqGSIb3DQEBCwUAA4ICAQBz
|
||||
4H1d5eGRU9bekUvi7LbZ5CP/I6w6PL/9AlXqO3BZKxplK7fYGHd3uqyDorJEsvjV
|
||||
hxwvFlEnS0JIU3nRzhJU/h4Yaivf1WLRFwGZ4TPBjX9KFU27exFWD3rppazkWybJ
|
||||
i4WuEdP3TJMdKLcNTtXWUDroDOgPlS66u6oZ+mUyUROil+B+fgQgVDhjRc5fvRgZ
|
||||
Lng8wuejCo3ExQyxkwn2G5guyIimgHmOQghPtLO5xlc67Z4GPUZ1m4tC+BCiFO4D
|
||||
YIXl3QiIpmU7Pss39LLKMGXXAgLRqyMzqE52lsznu18v5vDLfTaRH4u/wjzULhXz
|
||||
SrV1IUJmhgEXta4EeDmPH0itgKtkbwjgCOD7drrFrJq/EnvIaJ5cpxiI1pFmYD8g
|
||||
VVD7/KT/CyT1Uz1dI8QaP/JX8XEgtMJaSkPfjPErIViN9rh9ECCNLgFyv7Y0Plar
|
||||
A6YlvdyV1Rta/BHndf5Hqz9QWNhbFCMQRGVQNEcoKwpFyjAE9SXoKJvFIK/w5WXu
|
||||
qKzIYA26QXE3p734Xu1n8QiFJIyltVHbyUlD0k06194t5a2WK+/eDeReIsk0QOI8
|
||||
FGqhyPZ7YjR5tSZTmgljtViqBO5AA23QOVFqtjOUrjXP5pTbPJel99Z/FTkqSwvB
|
||||
Rt4OX7HfuokWQDTT0TMn5jVtJyi54cH7f9MmsNJ23g==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIEUzCCAjsCAQAwDjEMMAoGA1UEAwwDQm9iMIICIjANBgkqhkiG9w0BAQEFAAOC
|
||||
Ag8AMIICCgKCAgEAzQMXYOZz3ILrbF9qpDng2pw2wJf1UFopehwaYyu7riWJ9+AD
|
||||
rhSnCSFBM3ScMBc/8dIR6etWwci8QwJ/MtvIU0yx4llq+53G+19Bc1teC6q/b4QC
|
||||
RDIcTGxOZoR+jfYZVjPODEyJ5y5MZIo34ZP4bu+JnpT4W7+uojm3jOoyNPqXMcc7
|
||||
0uAhfSKG+JfrwZKteA4T5VKFytVcWgh4v03z8zTYeW3kD4lCsongBz6yu2dn3D6X
|
||||
MROnxiPwi+IRQqX1pwnJ0UA3CTeOHEw1jA3koxWIIg44PWaPaCj9Udrhf4ew00XL
|
||||
PWVZP8T5rVf8yUfecWQCR7FueJFqoLhPMMFi17rYmGZUvw3/YkXBjay4Q9e+G2WS
|
||||
3Xk8u+I1sCuVBJNBRv9DqtMC9D/N9NI8GkLrXwZmk82SXG+cQ0TSkNUHYI/03YKo
|
||||
qsn5H8PsG7Tc+Y2Ca6TaCWims7lvOg7U0E6lu2h5NGcdWHFPJ9qfe+xho/yfYYwG
|
||||
qEKanGAu1kd5SbIaX6/YiM5/Pp/96MeRNrB9kLzDnZTNuGtdCawVFgbkWmfX2Z6/
|
||||
a0d6SvZGDzBxxTVZRB0my01E1FP53MS8YRH98HUjGEwNRVq2e1W+aXldKppgZ85G
|
||||
ZD3l2YTeuI0iPJCDUzQiaWzFtWc8s13YQ1HLCOyOXF7QqMyNCiLGb4xQ56kCAwEA
|
||||
AaAAMA0GCSqGSIb3DQEBCwUAA4ICAQAn/ZI7IkBUEfhZHefwtF+QHCyxSEKvqwHq
|
||||
fSqKVdarBPz8Ik8m3icj8R/DcS3y5jgzx3x8bXQoDpgsAQgeb825NRv2wAQAGoH1
|
||||
8vh204lTyjqzrgtK7eQeQDc7fjeigIkxQsAK9zk4BaFUWp0wEC0RLVAgvlQTl7vu
|
||||
n1jSSrhK8tvGy62/cIxZfwD0bAMHlW4m1A4fUuSGWQX2KldgA8tnmT6wx0If/nKb
|
||||
VB68AMbyMHUeb32v9wEvx2nHlwMjqNFeg7vYyJXOfBdDILUl+OTBoQY1X+jSx5iM
|
||||
txTzmA8Hcgx0Fq+BnbQuZCLqFpNWEfenAtQtaAFuJwMiKCf6kgbqkDVShJkmt+vC
|
||||
j3dcsVMZDsdMk4qRpiJhaTQOYmsMGCj4uoDpFGjwPoUwlDkjYgHAAsm9uCkshc+m
|
||||
WZO7I6Z3Tbi3XskJvAMc3dTWjtc6nApEtr/mn8LcETfOp7RRSfjllj6ijWUrVwUy
|
||||
BpzU9C/zLTkhFX0DVDCIV+jEefF8JPfzSKLgXyRbInTz1/6/sKXtswXW0NjzqLMI
|
||||
C9ggMBhOiDv9KJn3G/mY4CqIfo9KMzF+++4t+wdXTir8DWNlMUAn1vlBwxZAgKCM
|
||||
GonVExBU0VIGCpyTRLkesEHnPMgybP6gLzP3++54x288OS5JwuPPtkDcsBHUjTq8
|
||||
HxTJvUul/Q==
|
||||
Ag8AMIICCgKCAgEA179eTsqcc1c3AOQHzCZEyYLPta2CCAscUFqcEZ9vWvjW0uzO
|
||||
v9TDlB33Unovjch4CElZOBhzTadVsbmnYKpxwyVU89WCuQKvedz4k1vu7S1YryfN
|
||||
bmS8PWbnQ4ds9NB7SgJNHZILvx9DXuWeFEyzRIo1984z4HheBzrkf791LqpYKaKz
|
||||
iANUo8h8t0dmTX/boOz8cEnQNwtTC0ZX3aD0obG/UAhr/22ZGPo/E659fh4ptyYX
|
||||
2LrIUHGy+EuxnJ9Y4cTqa88Ee6K6AkDiT/AoNQNxE4X++jqLuie8j/ZYpI1Oll38
|
||||
GwKVOyy1msRLtoGmISNwkMIQDGABrJlxgpP4QQAQ+08v9srzXOlkdxdr7OCP81r+
|
||||
ccBXiSQEe7BAkdJ8l98l5dprJ++GJ+SZcV4+/iGR0dKU2IdAG5HiKZIFn6ch9Ux+
|
||||
UMqeGaYCpkHrTiietHwcXgtVBlE0jFmB/HspmI/O0abK+grMmueaH7XtTI8YHnw0
|
||||
mUpL8+yp7mfA7zFusgFgyiBPXeD/NQgg8vja67k++d1VGoXm2xr+5WPQCSbgQoMk
|
||||
kOBMLHWJTefd6F4Z5M+oI0VwYbf6eQW246wJgpCHSPR0Vdijd6MAGRWKUuLfDsA9
|
||||
+12iGbKvwJ2enJlStft2V2LZcjBfdIMbigW1aSVNN5w6m6YVrQPry3WPkWcCAwEA
|
||||
AaAAMA0GCSqGSIb3DQEBCwUAA4ICAQCb07d2IjUy1PeHCj/2k/z9FrZSo6K3c8y6
|
||||
b/u/MZ0AXPKLPDSo7UYpOJ8Z2cBiJ8jQapjTSEL8POUYqcvCmP55R6u68KmvINHo
|
||||
+Ly7pP+xPrbA4Q0WmPnz37hQn+I1he0GuEQyjZZqUln9zwp67TsWNKxKtCH+1j8M
|
||||
Ltzx6kuHCdPtDUtv291yhVRqvbjiDs+gzdQYNJtAkUbHwHFxu8oZhg8QZGyXYMN8
|
||||
TGoQ1LTezFZXJtX69K7WnrDGrjsgB6EMvwkqAFSYNH0LFvI0xo13OOgXr9mrwohA
|
||||
76uZtjXL9B15EqrMce6mdUZi46QJuQ2avTi57Lz+fqvsBYdQO89VcFSmqu2nfspN
|
||||
QZDrooyjHrlls8MpoBd8fde9oT4uA4/d9SJtuHUnjgGN7Qr7eTruWXL8wVMwFnvL
|
||||
igWE4detO9y2gpRLq6uEqzWYMGtN9PXJCGU8C8m9E2EBUKMrT/bpNbboatLcgRrW
|
||||
acj0BRVqoVzk1sRq7Sa6ejywqgARvIhTehg6DqdMdcENCPQ7rxDRu5PSDM8/mwIj
|
||||
0KYl8d2PlECB4ofRyLcy17BZzjP6hSnkGzcFk0/bChZOSIRnwvKbvfXnB45hhPk8
|
||||
XwT/6UNSwC2STP3gtOmLqrWj+OE0gy0AkDMvP3UnQVGMUvgfYg+N4ROCVtlqzxe9
|
||||
W65c05Mm1g==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDNAxdg5nPcguts
|
||||
X2qkOeDanDbAl/VQWil6HBpjK7uuJYn34AOuFKcJIUEzdJwwFz/x0hHp61bByLxD
|
||||
An8y28hTTLHiWWr7ncb7X0FzW14Lqr9vhAJEMhxMbE5mhH6N9hlWM84MTInnLkxk
|
||||
ijfhk/hu74melPhbv66iObeM6jI0+pcxxzvS4CF9Iob4l+vBkq14DhPlUoXK1Vxa
|
||||
CHi/TfPzNNh5beQPiUKyieAHPrK7Z2fcPpcxE6fGI/CL4hFCpfWnCcnRQDcJN44c
|
||||
TDWMDeSjFYgiDjg9Zo9oKP1R2uF/h7DTRcs9ZVk/xPmtV/zJR95xZAJHsW54kWqg
|
||||
uE8wwWLXutiYZlS/Df9iRcGNrLhD174bZZLdeTy74jWwK5UEk0FG/0Oq0wL0P830
|
||||
0jwaQutfBmaTzZJcb5xDRNKQ1Qdgj/Tdgqiqyfkfw+wbtNz5jYJrpNoJaKazuW86
|
||||
DtTQTqW7aHk0Zx1YcU8n2p977GGj/J9hjAaoQpqcYC7WR3lJshpfr9iIzn8+n/3o
|
||||
x5E2sH2QvMOdlM24a10JrBUWBuRaZ9fZnr9rR3pK9kYPMHHFNVlEHSbLTUTUU/nc
|
||||
xLxhEf3wdSMYTA1FWrZ7Vb5peV0qmmBnzkZkPeXZhN64jSI8kINTNCJpbMW1Zzyz
|
||||
XdhDUcsI7I5cXtCozI0KIsZvjFDnqQIDAQABAoICAAN6aFLBqijNNFEM/95MKJVQ
|
||||
5eln0pbDxtUeZbC1yNv8IU56J5nUGh7gqG5m7bDvrgssXxcuwdStEwuYft+2JJyM
|
||||
Li7qyTK+YyY34CCExfBQ++k4jkDJsFr4Ee7xk8OVD6o7nATvpf3M9mkUwryyIdqA
|
||||
+B7fhGSrGHuCWuu6O/KT502GBazu1kadF7jfO/XXZxfEtl/zQdeWfdf9sY2+VPOU
|
||||
+5C41XARijcE+Y7p6IafKx8MlUxU+ulUygOXiOcucV/dfcXt7tkaTxAKF3T6Nd0x
|
||||
8/Ku9tOM2kVAP8b8HYwIOW7mLdvrbKOVNA61sdFY5axbD+JXP2pufiZ+pgJL36FF
|
||||
SDQIW5M3aH7CSa1i3i4MP49jWomhTNwseVrXsDuGCKVqgIR5LZwpS4VOHLAILkCh
|
||||
cIEDnoMS9YPuQdENIIxKyZGGHaeJ+LRb4w+szvtmu55Kp+N7AubPfoypPrx7a8LN
|
||||
8/0/w731DS6nTICYXXzzGoB3cefb3nsBNaH1+edffPTZOYlFZ9ElFjIs/xvWCSy4
|
||||
qYwQ1cW4DslIiVD62wm8Df2yr/5J6znfU01RXQ4GWfmDNFBdYsQO/8JEy6UZEvCy
|
||||
tFZ1gseD9K69O4XZSEKRKIvv8+1Y/CwD0ppIOYCIycTKn87GXFmsjbuj8tghmHp4
|
||||
TUi3EUvrw8mQMi5QBa5BAoIBAQD8JzdNy4ietoT8UUWqBT+ZSURPWeQN1esbncYU
|
||||
b9viBIznnjjFFr5JdYa5k3rxM+bTRq47NRt+r0HOvyJWUFJcI6tbgmGtW+rmM2kB
|
||||
hq6ekTJleLz+/cjNSjWD14avNORPz/ozZMlcz52NEl31pdniuDbueeNgyh+CkJtH
|
||||
BS8s8mMVZ+3NtafZ1ilGn/RP+n21C1J8Kcxd/1srtfcpybzAQiSYul2DlKVPGvqO
|
||||
XpLyt42/cyc7a3MyXtms2XhJ62fDK24Qptp6KJNTzqdtY+KP/iOW0SUgxf+JpC87
|
||||
W2NJW7tqyyaebn7KO1lGs9y03KzwaLZvy2RaBfjQnxS8uXzpAoIBAQDQI8QHNtr5
|
||||
nHYSzLZJMhJkP641wQWo4ODfkWxtEMqTyOXrVw3L8HMdA03Nmf9jnCv5awYYA3j0
|
||||
PmSL3PdM36d3VsAyyxMBN4HrH2Z94oTnoKmDfXjB3prhPYgO6aosSvE8rw1N055o
|
||||
757p9vAA5w9apBBLNdcm3cjUm2ZKeocL4wnFjOW63CtcFEouE4R7C32rauEu9Bdg
|
||||
dAXciBmOrHtihJUQrpMfyfN2fVSLbO4SoFy7ZHq5YKFk4MzNIp/cENwRIqdcLvOz
|
||||
o++RSbwptRtkd/HZCFSh/4gEPRLe/k5gGErS9ZqpeSMfV++IdBMqC0Sx3UpyXuue
|
||||
FOhIvnLpJlzBAoIBAGjcDh2mBLyr/oXHbocUA6zFUUkGgtZWHZ2wcQ1Sr0hAyDAS
|
||||
Fl2v5ZY677oA4OGpydYW0KICpdp7G4zU43ytjnKOytYVVHV5gigVPRfLYJbEnwaf
|
||||
vUj1VSo6MCMR4ArAnimqvcvdn/eex1BBUR20yPWF0iI+QhagN5ZeeJSCTWoNqrLe
|
||||
M4CWiKUIcMXUAw+3hctiV/0WjMySQuHcnFqecIYre3igF/9+M3jAKW5HWijhuGrj
|
||||
gm8tcgyCcVd2YJWs9cuuJel62eRvN0Vk7S+KmE91SmuPsjb84BXnV1UB3jpFkZ0J
|
||||
upesL8H+CFRku+Xi13Bqu2OmW6csUJrBbShGovECggEBAKGk9SupJXyvT1+gTn0f
|
||||
/vqOHiyvAEc8hkf6t5sobDtDzZPs4tEcpznEBBuF2rqwYdJtlKj3oWsGPa4FaKXy
|
||||
GCvtWozX+6V5R1Oj6kQftJnyw1NUEYF28Q+2asEyJTAK77jyNkHX9HGIjwEi/xek
|
||||
Wt9JBUJzyOjtW3gKS/HRoKnRpBghKZTqQl5bf5SzIbMxpGKJOeLuPG1zDc5MgJS2
|
||||
TYigcOgovCf2/jZqdUtmyKn8kqgSC+GGMzGWCFfT6RTOnypLoHBOIoPD8F0ER7aY
|
||||
aXKoWFH2T0wUmLy59brrA1FL7GhTx86QPn+sGmH9y5hecfY0ZwnVv+TgVdmQ1stN
|
||||
OMECggEBAOXDX319Dmo0ydAPYyngK4/slOetGaJmz8looU8a2R2+Ko/VMTZDmJhf
|
||||
P0vS74g3U7sukRjmYzUY1mPj27CDURvk1ENam9KPOQ59ws/TaHaJ7tobjUXVQ93/
|
||||
OREkrlCuqbEqJJzQ01mCWIbmDnGvJwD87rW6YwmI9Rs+kjZxNLj+IW4CqpY36q9A
|
||||
HwaUZLXc2q0W1CqLmFYF5HotvSFIAYHWuClEmM2NI9+0VItarBz6AwCnVXwKbJLC
|
||||
irXlllX+63uloTDR5W1ymy2hTUrhE1jgh9DR4106QSVDiEWqme/BAWmUoyuN/zms
|
||||
v3/WVVAXEcIowL3T4jzJ0RLdf1qE8Bc=
|
||||
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDXv15OypxzVzcA
|
||||
5AfMJkTJgs+1rYIICxxQWpwRn29a+NbS7M6/1MOUHfdSei+NyHgISVk4GHNNp1Wx
|
||||
uadgqnHDJVTz1YK5Aq953PiTW+7tLVivJ81uZLw9ZudDh2z00HtKAk0dkgu/H0Ne
|
||||
5Z4UTLNEijX3zjPgeF4HOuR/v3UuqlgporOIA1SjyHy3R2ZNf9ug7PxwSdA3C1ML
|
||||
RlfdoPShsb9QCGv/bZkY+j8Trn1+Him3JhfYushQcbL4S7Gcn1jhxOprzwR7oroC
|
||||
QOJP8Cg1A3EThf76Oou6J7yP9likjU6WXfwbApU7LLWaxEu2gaYhI3CQwhAMYAGs
|
||||
mXGCk/hBABD7Ty/2yvNc6WR3F2vs4I/zWv5xwFeJJAR7sECR0nyX3yXl2msn74Yn
|
||||
5JlxXj7+IZHR0pTYh0AbkeIpkgWfpyH1TH5Qyp4ZpgKmQetOKJ60fBxeC1UGUTSM
|
||||
WYH8eymYj87Rpsr6Csya55ofte1MjxgefDSZSkvz7KnuZ8DvMW6yAWDKIE9d4P81
|
||||
CCDy+NrruT753VUahebbGv7lY9AJJuBCgySQ4EwsdYlN593oXhnkz6gjRXBht/p5
|
||||
BbbjrAmCkIdI9HRV2KN3owAZFYpS4t8OwD37XaIZsq/AnZ6cmVK1+3ZXYtlyMF90
|
||||
gxuKBbVpJU03nDqbphWtA+vLdY+RZwIDAQABAoICAETxu6J0LuDQ+xvGwxMjG5JF
|
||||
wjitlMMbQdYPzpX3HC+3G3dWA4/b3xAjL1jlAPNPH8SOI/vAHICxO7pKuMk0Tpxs
|
||||
/qPZFCgpSogn7CuzEjwq5I88qfJgMKNyke7LhS8KvItfBuOvOx+9Ttsxh323MQZz
|
||||
IGHrPDq8XFf1IvYL6deaygesHbEWV2Lre6daIsAbXsUjVlxPykD81nHg7c0+VU6i
|
||||
rZ9WwaRjkqwftC6G8UVvQCdt/erdbYv/eZDNJ5oEdfPX6I3BHw6fZs+3ilq/RSoD
|
||||
yovRozS1ptc7QY/DynnzSizVJe4/ug6p7/LgTc2pyrwGRj+MNHKv73kHo/V1cbxF
|
||||
fBJCpxlfcGcEP27BkENiTKyRQEF1bjStw+UUKygrRXLm3MDtAVX8TrDERta4LAeW
|
||||
XvPiJbSOwWk2yYCs62RyKl+T1no7alIvc6SUy8rvKKm+AihjaTsxTeACC1cBc41m
|
||||
5HMz1dqdUWcB5jbnPsV+27dNK1/zIC+e0OXtoSXvS+IbQXo/awHJyXv5ClgldbB9
|
||||
hESFTYz/uI6ftuTM6coHQfASLgmnq0fOd1gyqO6Jr9ZSvxcPNheGpyzN3I3o5i2j
|
||||
LTYJdX3AoI5rQ5d7/GS2qIwWf0q8rxQnq1/34ABWD0umSa9tenCXkl7FIB4drwPB
|
||||
4n7n+SL7rhmv0vFKIjepAoIBAQD19MuggpKRHicmNH2EzPOyahttuhnB7Le7j6FC
|
||||
afuYUBFNcxww+L34GMRhmQZrGIYmuQ3QV4RjYh2bowEEX+F5R1V90iBtYQL1P73a
|
||||
jYtTfaJn0t62EBSC//w2rtaRJPgGhbXbnyid64J0ujRFCelej8FRJdBV342ctRAL
|
||||
0RazxQ/KcTRl9pncALxGhnSsBElZlDtZd/dWnWBDZ/fg/C97VV9ZQLcpyGvL516i
|
||||
GpB8BQsHiIe9Jt5flZvcKB7z/KItGzPB4WK6dpV8t/FeQiUpZXkQlqO03XaZT4NP
|
||||
AEGH3rKIRMpP7TORYFhbYrZwov3kzLaggax2wGPTkfMFNlTjAoIBAQDgjsYfShkz
|
||||
6Dl1UTYBrDMy9pakJbC6qmd0KOKX+4XH/Dc1mOzR8NGgoY7xWXFUlozgntKKnJda
|
||||
M6GfOt/dxc0Sq7moYzA7Jv4+9hNdU3jX5YrqAbcaSFj6k4yauO2BKCBahQo8qseY
|
||||
a3N5f0gp+5ftTMvOTwGw3JRJFJq0/DvKWAYLIaJ0Oo77zGs0vxa1Aqob10MloXt5
|
||||
DMwjazWujntTzTJY1vsfsBHa8OEObMwiftqnmn6L4Qprd3AzQkaNlZEsvERyLfFq
|
||||
1pu4EsDJJGdVfpZYfo+6vTglLXFBLEUQmh4/018Mw4O4pGgCVMj/wict/gTViQGC
|
||||
qSj+IOThsTytAoIBAHu3L3nEU/8EwMJ54q0a/nW+458U3gHqlRyWCZJDhxc9Jwbj
|
||||
IMoNRFj39Ef3VgAmrMvrh2RFsUTgRG5V1pwhsmNzmzAXstHx2zALaO73BZ7wcfFx
|
||||
Yy8G9ZpTMsU6upj1lICLX0diTmbo4IzgYIxdiPJUsvOjZqDbOvsZJEIdYSL5u5Cj
|
||||
0qx7FzdPc2SyGxuvaEnTwuqk6le5/4LIWCnmD+gksDpP0BIHSxmcfsBhRk3rp3mZ
|
||||
llVxqKdBtM1PrQojCFxR833RZfzOyzCZwaIc+V5SOUw7yYqfXxmMokrpoQy72ueq
|
||||
Wm1LrgWxBaCqDYSop7cftbkUoPB2o3/3SNtVUesCggEAReqOKy3R/QRf53QaoZiw
|
||||
9DwsmP0XMndd8J/ONU3d0G9p7SkpCxC05BOJQwH7NEAPqtwoZ3nr8ezDdKVLEGzG
|
||||
tfp7ur7vRGuWm5nYW6Viqa3Re5x/GxLNiW8pRv8vC5inwidMEamGraE++eQ0XsXz
|
||||
/rF7f0fAGgYDsWFV7eXe49hWQV7+iru0yxdRhcG9WyxyNGrogC3wGLdwU9LMiwXX
|
||||
xjbMZzbAR5R1arq3B9u+Dzt57tc+cWTm7qDocT1AZFLeOZSApyBA22foYf6MwdOw
|
||||
zMC2JOV68MR7V6/3ZDhZZJrnsi2omXvCZlnh/F/TmTYlJr/BV47pxnnOxpkNSmv5
|
||||
nQKCAQBRqrsUVO7NOgR1sVX7YDaekQiJKS6Vq/7y2gR4FoLm/MMzNZQgGo9afmKg
|
||||
F2hSv6tuoqc33Wm0FnoSEMaI8ky0qgA5kwXvhfQ6pDf/2zASFBwjwhTyJziDlhum
|
||||
iwWe1F7lNaVNpxAXzJBaBTWvHznuM42cGv5bbPBSRuIRniGsyn/zYMrISWgL+h/Q
|
||||
fsQ2rfPSqollPw+IUPN0mX+1zg6PFxaR4HM9UrRX7cnRKG20GIDPodsUl8IMg+SO
|
||||
M5YG/UqDD10hfeEutvQIvl0oJraBWT34cqUZLVpUwJzf1be7zl9MzHGcym/ni7lX
|
||||
dg6m3MAyZ1IXjHlogOdmGvnq07/w
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRIwEAYDVQQDDAlsb2Nh
|
||||
bGhvc3QxIDAeBgNVBAoMF0NsaWVudCBDZXJ0aWZpY2F0ZSBEZW1vMB4XDTI1MDcy
|
||||
MTE1NTYxOFoXDTM1MDcxOTE1NTYxOFowEDEOMAwGA1UEAwwFQWxpY2UwggIiMA0G
|
||||
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC4ggn74iAHLgOWOiOvB2CPe+Hr7W6S
|
||||
TYJLZOoqPdh7mv7QGm8cYxfD+26p13aEaW4/qn45losWdEPPy2ZiVIF+kcOP0R4A
|
||||
qsB0w9UHT4WSzCWtDqs8ywDMJ6tHge0++8S1bTpdutn/m8DPnKtkD9RQUzLFmGDO
|
||||
+mB08Xu+egTzJvURbHXRJ27E+CXUXLEHbAJd8EKjJiQYXhcj4lzUXOUg+xkpPAGe
|
||||
1dgQ6BDkv3xq/81S9NTIT5YriHEm6egi9AFJLZbbZtCpRQm1MDMq7zfD7oL6ECLG
|
||||
rJ/aaxLEM49gMdw2SscYHotVxX2OMAKgN/ytB18L/mIQ4pOWp3HJQ+nks9Zu1V8c
|
||||
g7Pz5pWwjqoncbyUaBi3vGsitAot3cyLXbN9hH8zQB8QqGyNLvqQnCJOBlYxOPA8
|
||||
M8NQGDThWKspcix0LhkmnYsWWt3+KEGEpFRcJCEthm/DAd1GImP7/dg1/btT/zOs
|
||||
IIkIoCyBwznuR4M4XoNTbIBsiTnO/6PjOdTrjLVX7vMueTjdbCgK3VeOuwetbZ7a
|
||||
Z/hvMJCjJ4wuM3l2ZyfEQlP4gJLJS3Fw2PRsySZJl9JyEzwTqYVosDF5SF8uw0HI
|
||||
cFaliZCqBbgYfOiQzjIX/GiHZdor1ZrhAbO/MpSxuxGzxF7Em4n+4p816NnC9S2J
|
||||
bHRetkM9P1adHwIDAQABo0IwQDAdBgNVHQ4EFgQUXhGloOgfXb0tY7HZZGil/d11
|
||||
bcwwHwYDVR0jBBgwFoAU8doR+Mmgh+1KQdNvybCZ7bsu2J8wDQYJKoZIhvcNAQEL
|
||||
BQADggIBADNVu8YodDjB0474ztGSjV8WO0x984WQpGG6VPIt9xnnswNM8aOZVMNC
|
||||
AS12BjgviutSBUbL40xYNlytnqP0KtlgZSNpPVTGMAOoGttbgV7w46+hyBgV4hYs
|
||||
PsYrxMU1/4hTW/aGnNXpWJ4VwOESknSqUudzfy1mNVaEuPoL97SCvPrlKPU6El1a
|
||||
Wmove/QTKsbsjWaahqE59uClQ6CBcWbxpN5CLyIVM4c/UrsoXdwRewgXl19YFRzR
|
||||
l6LXBPid4UPQqdE6XIxgsNpoTDwAyxSRMPydlulJD5sSTaXHB7h63DsT9mEydjR3
|
||||
jPjhNZL5ADtDes3/UhfpXDbb8MudXdbdsHNswEl5ewAOdRXAuoaJuQ2TOnhz+cO0
|
||||
oaq9X3YaWjl8SwdvZrLIHLG3jEAQYEXDR+dEtT6vs7HmReMrYhGGoCEVrjSZAaeO
|
||||
9bQoSe0m8xbuSV19e5A+LZv3bcPcVOe91x/wnjVb98KRQcSQXCBE3yT5Oav/OLKZ
|
||||
TrdRkKe1yyPMHJiicn3pffdXuG6mIJC8HgYhvJEX/wkWf1BiyRd44dD1cgI1Ttt1
|
||||
pQoapJCmjA0XHtr15o4TW6hmnrmOOYTOVCCug8h1bWscBedMgdR5Qm+umbUiuC3N
|
||||
N6mxD49Sc40NCeDboX87rDiObhOXAAFsiE9o39z/tPToVa3TsJsA
|
||||
bGhvc3QxIDAeBgNVBAoMF0NsaWVudCBDZXJ0aWZpY2F0ZSBEZW1vMB4XDTI0MDcx
|
||||
OTEyNDczN1oXDTI1MDcxOTEyNDczN1owEDEOMAwGA1UEAwwFQWxpY2UwggIiMA0G
|
||||
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCac3+4rNmH4/N1s4HqR2X168tgS/aA
|
||||
6sHW5at8mWRnq54Nm11RvnK55jHQYVAdBgJy5M07w0wakp8inxzlY95wqxBimYG6
|
||||
3Un/1p7mX9FkB4LNISCc6j/s/Ufv85MXPbn0S5rm9UcQO9cINJb1RP1YgDDLN5cx
|
||||
Mz6X4nyofN8H6Lhvh4JDdBw4DfDEFERkVfF+bkZ7YW4XHEChgzm3RxCF0eeGzIXG
|
||||
rkkK9AsSdJAhOvTlHPFCQKXTYZhsL5+3Ma4RnWnDWvLTHx6KzoU+twTM2mYhhQuQ
|
||||
gQpnmDHxGge8kGeHGtfdgAjtVJTE57xF/shP0JU+tuIV8NNhQ/vEmhL0Wa093/Ev
|
||||
pTVp0EUEuDh9ORRH5K5M4bKJyU4XX5noiht6yOn00uaoJcWduUAWsU+cDSvDTMw8
|
||||
1opWWm0QIAV3G2yuRSkumHAKqvQLeyeyiKz+OEhyEiZ7EZNExPD0TSpApSTU6aCT
|
||||
UAvPYGQ59VjsMHTuJ9r4wKIYaDvfL+t72vg2vTQma5cTOBJfIdxH9blFTjEnToH3
|
||||
LX8t0XndQ2RkiRnIze2p2jUShxo/lWCjCw+2Iaw0A0fNUK1BbOrFRPq1u7AnEuMJ
|
||||
t7HF50MloItM97R9vofDwgDIzlX/PzlVRcn1WCo8Fr/0EXxPPreX0YDIp1ANQ8fS
|
||||
v7bKb2vQIxWuCQIDAQABo0IwQDAdBgNVHQ4EFgQUVJVRJJ2k/Z4r0M1AXe6agyD4
|
||||
uCwwHwYDVR0jBBgwFoAUEHtrxWCk96Ehr60E0HBuwLk2i+IwDQYJKoZIhvcNAQEL
|
||||
BQADggIBAGEvSkxhxRKmlvKG8wCXop2OaUUAOG16+T96vd+aFYaJNlfGoPvqv4Lw
|
||||
qaHztVktnRrJ//fpNWOsdxkE1uPU4uyGjl2KbyH81JvkE6A3OX0P4B01n8lcimY2
|
||||
j3oje6KjORUouYVsypD1VcwfWJgsE3U2Txv5srD8BoemVWgWbWjfyim4kk8C5zlf
|
||||
tWEazVAaI4MWecqtU4P5gIEomCI7MG9ebxYp5oQhRxeOndOYdUbSzAkZj50gXFA1
|
||||
+TNkvuhTFlJF0F7qIFVJSJTmJ+6E5B4ddbkyUYwbOdO+P8mz5N5mSljE+EiIQTxo
|
||||
AwbG8cSivMy/jI3h048tCUONAJzcSWCF4k1r9Qr6xbyW2ud2GmKiFCEYJkYTsMWV
|
||||
fM/RujTHlGvJ2+bQK5HiNyW0tO9znW9kaoxolu1YBvTh2492v3agK7nALyGGgdo1
|
||||
/nN/ikgkQiyaCpZwFeooJv1YFU5aDhR9RjIIJ9UbJ8FdAv8Xd00E3viunLTvqqXK
|
||||
RVMokw+tFQTEzjKofKWYArPDjB9LUbN+vQbumKalis3+NlJ3WolYPrCg55tqt1o3
|
||||
zXi+xv7120cJFouilRFwrafNFV6F+pRMkMmiWopMnoVJPVXcoqyJRcsmO62uslhg
|
||||
BLFgAH4H/14drYrgWIMz0no78RInEz0z507zwLkWk5d9W9pJ/4Rf
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user