Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9dbd56765 |
@@ -1,115 +0,0 @@
|
||||
{
|
||||
"hydrated": false,
|
||||
"properties": {
|
||||
"helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/suppressions",
|
||||
"hydrationStatus": "This file does not contain identifying data. It is safe to check into your repo. To hydrate this file with identifying data, run `guardian hydrate --help` and follow the guidance."
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"suppressionSets": {
|
||||
"default": {
|
||||
"name": "default",
|
||||
"createdDate": "2024-02-06 20:37:57Z",
|
||||
"lastUpdatedDate": "2024-02-06 20:37:57Z"
|
||||
}
|
||||
},
|
||||
"results": {
|
||||
"de854c6ab9b27b1ec642cec1a51059b92f88815a231c1c8f4b8e71d9e378f174": {
|
||||
"signature": "de854c6ab9b27b1ec642cec1a51059b92f88815a231c1c8f4b8e71d9e378f174",
|
||||
"alternativeSignatures": [
|
||||
"79827cf2e75a7f99eec716562fb9fa0d49014ac96b7afc76d29d79a33e8edd94"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"ebe0026db71ae4bb2d8e76b706198003079a5c095658de8dd49e67f7e572ea46": {
|
||||
"signature": "ebe0026db71ae4bb2d8e76b706198003079a5c095658de8dd49e67f7e572ea46",
|
||||
"alternativeSignatures": [],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"bb02ef965dce40b6c950b6d0cf8a9f41c08c5e33f17268fb208f3687b11ffa26": {
|
||||
"signature": "bb02ef965dce40b6c950b6d0cf8a9f41c08c5e33f17268fb208f3687b11ffa26",
|
||||
"alternativeSignatures": [
|
||||
"3a8630eaccc2c5c39ae78836bb115bf55557058bad206fdad7dbe4f0ae466ed1"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"dffa3e24f6dc7542d741b2fab22eec657aca441a51cee515ca9bb4932995a416": {
|
||||
"signature": "dffa3e24f6dc7542d741b2fab22eec657aca441a51cee515ca9bb4932995a416",
|
||||
"alternativeSignatures": [
|
||||
"56a4b454840e2c21d44a76d9ab09fde76fba682ce7508a3f6abf7b411d389e56"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"5dbcaaac8cdccc6df557cbde94e5d7e0f1c8a67546ba82a1b85b629030f3d311": {
|
||||
"signature": "5dbcaaac8cdccc6df557cbde94e5d7e0f1c8a67546ba82a1b85b629030f3d311",
|
||||
"alternativeSignatures": [
|
||||
"fdb8e8af8d5697f767d0e55194f91d4a089d981555e00d058ba866acb8602014"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"b7db026b2a60bdb63af1c0938ac16d9414bb4d38e9efdc51626e12aa55f6b72f": {
|
||||
"signature": "b7db026b2a60bdb63af1c0938ac16d9414bb4d38e9efdc51626e12aa55f6b72f",
|
||||
"alternativeSignatures": [
|
||||
"bf7bb897e644659827d8dc8d55f719296d3ab94dc750b666ce90d8057361d9d5"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"aa702d85554c352e3016e3ec3d790df489833dc97e3733c58b57915ec125f47b": {
|
||||
"signature": "aa702d85554c352e3016e3ec3d790df489833dc97e3733c58b57915ec125f47b",
|
||||
"alternativeSignatures": [
|
||||
"948787329d52a66b4691383c81af407b03e68344a6685bbab3cfa8eb8db34f81"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"38174b5c9b474c3c0278d4c4173c14022e03dec3dc4db5ced51d2ca8459e7f2a": {
|
||||
"signature": "38174b5c9b474c3c0278d4c4173c14022e03dec3dc4db5ced51d2ca8459e7f2a",
|
||||
"alternativeSignatures": [
|
||||
"a9efa99679f3966da96a8b89f1250576cfceda774556d43ea89ea84289967276"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"08a4e1be4662d897e5b2b7a7dc6d6901405462cd2d5f8ad433c13e12a8503fb6": {
|
||||
"signature": "08a4e1be4662d897e5b2b7a7dc6d6901405462cd2d5f8ad433c13e12a8503fb6",
|
||||
"alternativeSignatures": [
|
||||
"009132f89939956a3f4471bb13353394015c9a7e675d118aa427e75f05658e05"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
},
|
||||
"551d69737553150380e58bc9a8ae1e8f17da931561ea4e195781fb8cad225188": {
|
||||
"signature": "551d69737553150380e58bc9a8ae1e8f17da931561ea4e195781fb8cad225188",
|
||||
"alternativeSignatures": [
|
||||
"617ad56322c5fb82a162b0b583e676d66a8e76b0d444aaab487865e4bf89e83b"
|
||||
],
|
||||
"memberOf": [
|
||||
"default"
|
||||
],
|
||||
"createdDate": "2024-02-06 20:37:57Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
pr: none
|
||||
|
||||
trigger:
|
||||
tags:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
- repository: 1esPipelines
|
||||
type: git
|
||||
name: 1ESPipelineTemplates/1ESPipelineTemplates
|
||||
ref: refs/tags/release
|
||||
|
||||
extends:
|
||||
template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
|
||||
parameters:
|
||||
pool:
|
||||
name: DevDivPlaywrightAzurePipelinesUbuntu2204
|
||||
os: linux
|
||||
sdl:
|
||||
sourceAnalysisPool:
|
||||
name: DevDivPlaywrightAzurePipelinesWindows2022
|
||||
# The image must be windows-based due to restrictions of the SDL tools. See: https://aka.ms/AAo6v8e
|
||||
# In the case of a windows build, this can be the same as the above pool image.
|
||||
os: windows
|
||||
suppression:
|
||||
suppressionFile: $(Build.SourcesDirectory)\.azure-pipelines\guardian\SDL\.gdnsuppress
|
||||
stages:
|
||||
- stage: Stage
|
||||
jobs:
|
||||
- job: Build
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
path: $(Build.ArtifactStagingDirectory)/esrp-build
|
||||
artifact: esrp-build
|
||||
steps:
|
||||
- bash: |
|
||||
if [[ ! "$CURRENT_BRANCH" =~ ^v1\..* ]]; then
|
||||
echo "Can only publish from a release tag branch (v1.*)."
|
||||
echo "Unexpected branch name: $CURRENT_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
CURRENT_BRANCH: ${{ variables['Build.SourceBranchName'] }}
|
||||
displayName: "Check the branch is a release branch"
|
||||
|
||||
- bash: |
|
||||
echo "importing GPG key:"
|
||||
# Pipeline variables do not preserve line ends so we use base64 instead of --armored as a workaround.
|
||||
echo $GPG_PRIVATE_KEY_BASE64 | base64 -d | gpg --batch --import
|
||||
echo "list keys after import:"
|
||||
gpg --list-keys
|
||||
env:
|
||||
GPG_PRIVATE_KEY_BASE64: $(GPG_PRIVATE_KEY_BASE64) # secret variable has to be mapped to an env variable
|
||||
displayName: "Import gpg key"
|
||||
|
||||
- bash: ./scripts/download_driver.sh
|
||||
displayName: 'Download driver'
|
||||
|
||||
- bash: mvn -B deploy -D skipTests --no-transfer-progress --activate-profiles release -D gpg.passphrase=$GPG_PASSPHRASE -DaltDeploymentRepository=snapshot-repo::default::file:$(Build.ArtifactStagingDirectory)/esrp-build
|
||||
displayName: 'Build and deploy to a local directory'
|
||||
env:
|
||||
GPG_PASSPHRASE: $(GPG_PASSPHRASE) # secret variable has to be mapped to an env variable
|
||||
|
||||
- job: Publish
|
||||
dependsOn: Build
|
||||
templateContext:
|
||||
type: releaseJob
|
||||
isProduction: true
|
||||
inputs:
|
||||
- input: pipelineArtifact
|
||||
artifactName: esrp-build
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/esrp-build
|
||||
steps:
|
||||
- checkout: none
|
||||
- task: EsrpRelease@9
|
||||
inputs:
|
||||
connectedservicename: 'Playwright-ESRP-PME'
|
||||
usemanagedidentity: true
|
||||
keyvaultname: 'playwright-esrp-pme'
|
||||
signcertname: 'ESRP-Release-Sign'
|
||||
clientid: '13434a40-7de4-4c23-81a3-d843dc81c2c5'
|
||||
intent: 'PackageDistribution'
|
||||
contenttype: 'Maven'
|
||||
# Keeping it commented out as a workaround for:
|
||||
# https://portal.microsofticm.com/imp/v3/incidents/incident/499972482/summary
|
||||
# contentsource: 'folder'
|
||||
folderlocation: '$(Build.ArtifactStagingDirectory)/esrp-build'
|
||||
waitforreleasecompletion: true
|
||||
owners: 'yurys@microsoft.com'
|
||||
approvers: 'yurys@microsoft.com'
|
||||
serviceendpointurl: 'https://api.esrp.microsoft.com'
|
||||
mainpublisher: 'Playwright'
|
||||
domaintenantid: '975f013f-7f24-47e8-a7d3-abc4752bf346'
|
||||
displayName: 'ESRP Release to Maven'
|
||||
@@ -1,76 +0,0 @@
|
||||
---
|
||||
name: playwright-java-release
|
||||
description: Prepare a Playwright Java release after the rolling PR has merged — cut the release branch, mark the Maven version, draft the GitHub release, and tick the Java boxes in the internal checklist.
|
||||
---
|
||||
|
||||
Use this skill once the `chore: roll driver to 1.X.0` PR has merged into `main` and the upstream JS `v1.X.0` is published. The rolling work itself is covered by the [[playwright-roll]] skill.
|
||||
|
||||
Throughout this doc, replace `X` with the minor version (e.g. `60` for `1.60.0`) and `<user>` with the fork owner (`gh api user --jq .login`).
|
||||
|
||||
The full release checklist lives in the private `microsoft/playwright-internal` repo as the `v1.X checklist` issue. Find its number once:
|
||||
|
||||
```bash
|
||||
unset GITHUB_TOKEN
|
||||
ISSUE=$(gh search issues --repo microsoft/playwright-internal "v1.X checklist" --json number --jq '.[0].number')
|
||||
```
|
||||
|
||||
Tick each Java box incrementally (one PATCH per item) so the issue reflects accurate state if the flow is interrupted:
|
||||
|
||||
```bash
|
||||
gh api repos/microsoft/playwright-internal/issues/$ISSUE --jq '.body' > /tmp/body.md
|
||||
# edit /tmp/body.md to flip "- [ ]" → "- [x]" on the relevant Java item
|
||||
gh api repos/microsoft/playwright-internal/issues/$ISSUE -X PATCH --field body=@/tmp/body.md
|
||||
```
|
||||
|
||||
## 1. Cut the release branch
|
||||
|
||||
Push `release-1.X` from current `upstream/main` (which now contains the merged roll commit):
|
||||
|
||||
```bash
|
||||
git fetch upstream main
|
||||
git push upstream upstream/main:refs/heads/release-1.X
|
||||
```
|
||||
|
||||
## 2. Draft the GitHub release
|
||||
|
||||
Generate the release notes from the upstream docs:
|
||||
|
||||
```bash
|
||||
cd ~/playwright
|
||||
node utils/render_release_notes.mjs java 1.X > /tmp/v1.X.0-release-notes.md
|
||||
```
|
||||
|
||||
The renderer leaves JS-isms that need fixing for Java. Apply these substitutions — the list is not exhaustive, eyeball the diff before publishing:
|
||||
|
||||
- `toMatchAriaSnapshot()` → `matchesAriaSnapshot()`
|
||||
- `toHaveCSS()` → `hasCSS()` (and other `toHaveX` matchers → `hasX`)
|
||||
- `browser.on('context')` → `browser.onContext()`
|
||||
- `browserContext.on('download' | 'frameattached' | ...)` → `browserContext.onDownload()` / `onFrameAttached()` / …
|
||||
|
||||
Create the draft directly against `release-1.X` — drafting against `main` and retargeting later is fragile because every `gh release edit` rotates the `untagged-<hash>` ID:
|
||||
|
||||
```bash
|
||||
gh release create v1.X.0 --repo microsoft/playwright-java --draft \
|
||||
--title "v1.X.0" --notes-file /tmp/v1.X.0-release-notes.md --target release-1.X
|
||||
```
|
||||
|
||||
## 3. Bump the Maven version on the release branch
|
||||
|
||||
Cut `mark-v-1.X.0` off `upstream/release-1.X`, run `set_maven_version.sh`, and PR back to the release branch:
|
||||
|
||||
```bash
|
||||
git checkout -b mark-v-1.X.0 upstream/release-1.X
|
||||
./scripts/set_maven_version.sh 1.X.0
|
||||
git add -u
|
||||
git commit -m "chore: mark 1.X.0"
|
||||
git push -u origin mark-v-1.X.0
|
||||
gh pr create --repo microsoft/playwright-java --head <user>:mark-v-1.X.0 --base release-1.X \
|
||||
--title "chore: mark 1.X.0" \
|
||||
--body "Updates Maven version in all modules to \`1.X.0\` for the v1.X release."
|
||||
```
|
||||
|
||||
`set_maven_version.sh` only invokes `mvn versions:set` on `pom.xml`, `tools/*/pom.xml`, and `examples/pom.xml`, but the root invocation cascades through the reactor, so the expected diff is 11 poms: root + `driver/` + `driver-bundle/` + `playwright/` (from the reactor cascade) + 6 under `tools/` + `examples/`, all flipping `1.<prev>.0-SNAPSHOT` → `1.X.0`. Any other file in the diff is a red flag.
|
||||
|
||||
## 4. Publish
|
||||
|
||||
The user publishes the draft release manually once the `mark-v-1.X.0` PR is merged. After publishing, CI pushes the artifacts to Maven Central and runs the Docker workflow automatically: https://github.com/microsoft/playwright-java/actions.
|
||||
@@ -1,202 +0,0 @@
|
||||
---
|
||||
name: playwright-roll
|
||||
description: Roll Playwright Java to a new version
|
||||
---
|
||||
|
||||
Help the user roll to a new version of Playwright.
|
||||
ROLLING.md contains general instructions and scripts.
|
||||
|
||||
Start with running ./scripts/roll_driver.sh to update the version and generate the API to see the state of things.
|
||||
Afterwards, walk through the upstream changes that affect the Java client and port the relevant ones.
|
||||
|
||||
## Determining what to port
|
||||
|
||||
List the upstream commits that touched a client-relevant path since the last release. The paths cover everything that can change the public Java surface or the wire protocol:
|
||||
|
||||
- `docs/src/api/` — the source of truth for `api.json`. Method/option additions, removals, and `langs:` filter changes flow from here.
|
||||
- `packages/playwright-core/src/client/` — the JS client implementation that the Java client mirrors.
|
||||
- `packages/isomorphic/` — selector engines, locator generation/parsing, and aria-snapshot logic shared between client and server. Changes here can affect client-side helpers like `getByRoleSelector`.
|
||||
- `packages/playwright/src/matchers/matchers.ts` — assertion-method definitions. Changes here usually correspond to new options on `LocatorAssertions` / `PageAssertions`.
|
||||
- `packages/protocol/src/protocol.yml` — the wire protocol schema. Method/event additions, parameter renames, and result-shape changes affect what the Java `*Impl` classes need to send/receive.
|
||||
|
||||
```bash
|
||||
cd ~/playwright
|
||||
PREV_TAG=$(git tag | grep -E '^v1\.[0-9]+\.[0-9]+$' | sort -V | tail -1) # e.g. v1.59.1
|
||||
git log "$PREV_TAG"..HEAD --oneline -- \
|
||||
'docs/src/api/' \
|
||||
'packages/playwright-core/src/client/' \
|
||||
'packages/isomorphic/' \
|
||||
'packages/playwright/src/matchers/matchers.ts' \
|
||||
'packages/protocol/src/protocol.yml'
|
||||
```
|
||||
|
||||
Walk that list top-to-bottom (oldest-first is easier — newest is at top, so reverse). For each commit:
|
||||
1. Read the commit (`git show <sha>`) to see what client/protocol/docs changed.
|
||||
2. If it's JS-internal (bundling, dispatcher conventions, electron, mcp, dashboard, trace-viewer, test-runner) — skip.
|
||||
3. If it touches `docs/src/api/` or types, check `langs:` annotations — features marked `langs: js`/`langs: js, python` don't apply to Java.
|
||||
4. If it adds/changes a public API method or option that applies to Java, port it. The api.json regenerated by `roll_driver.sh` already contains the new types/options, so the generated Java interfaces usually pick them up automatically — what's typically missing is the `*Impl` wiring.
|
||||
5. Watch for follow-up reverts — a "feat: X" commit might be undone by a later "Revert X". Check whether the change still exists in HEAD before porting.
|
||||
6. Maintain a running notes file (e.g. `/tmp/roll-notes.md`) listing each upstream PR as ported / skipped / verified-already-supported, with a one-line reason. This file becomes the body of the eventual PR.
|
||||
|
||||
## What to include in the rolling PR
|
||||
|
||||
- Driver version bump
|
||||
- Generated interface diffs from `roll_driver.sh`
|
||||
- `*Impl` wiring for each ported feature
|
||||
- Generator updates (import lists, special-cases) if new types appeared
|
||||
- A small test per new public API surface — listener for new events, basic call for new methods, regression for changed return types
|
||||
- PR description: list each upstream PR ported, each skipped (with reason), and each verified-already-supported
|
||||
|
||||
Rolling includes:
|
||||
- updating client implementation to match changes in the upstream JS implementation (see ../playwright/packages/playwright-core/src/client)
|
||||
- adding a couple of new tests to verify new/changed functionality
|
||||
|
||||
## Mimicking the JavaScript implementation
|
||||
|
||||
The Java client is a port of the JS client in `../playwright/packages/playwright-core/src/client/`. When implementing a new or changed method, always read the corresponding JS file first and mirror its logic:
|
||||
|
||||
```
|
||||
../playwright/packages/playwright-core/src/client/browserContext.ts
|
||||
../playwright/packages/playwright-core/src/client/page.ts
|
||||
../playwright/packages/playwright-core/src/client/tracing.ts
|
||||
../playwright/packages/playwright-core/src/client/video.ts
|
||||
../playwright/packages/playwright-core/src/client/locator.ts
|
||||
../playwright/packages/playwright-core/src/client/network.ts
|
||||
...
|
||||
```
|
||||
|
||||
Key translation rules:
|
||||
|
||||
**Protocol calls** — `await this._channel.methodName(params)` → `sendMessage("methodName", params, NO_TIMEOUT)`
|
||||
|
||||
**Extracting a returned channel object from a result** — JS uses `SomeClass.from(result.foo)` which resolves the JS-side object for a channel reference. In Java, the object was already created when the server sent `__create__`, so extract it from the connection: `connection.getExistingObject(result.getAsJsonObject("foo").get("guid").getAsString())`
|
||||
|
||||
**Async/await** — all `await` calls become synchronous `sendMessage(...)` calls since the Java client is synchronous.
|
||||
|
||||
**`undefined` / optional params** — JS `options?.foo` checks translate to `if (options != null && options.foo != null)` null checks before adding to the params `JsonObject`.
|
||||
|
||||
**`_channel` fields** — the JS `this._channel.foo` maps to calling `sendMessage("foo", ...)` on `this` in the Impl class.
|
||||
|
||||
**Channel object references in params** — when a JS call passes a channel object as a param (e.g. `{ frame: frame._channel }`), in Java pass the guid: `params.addProperty("frame", ((FrameImpl) frame).guid)`.
|
||||
|
||||
## Fixing generator and compilation errors
|
||||
|
||||
After running `./scripts/roll_driver.sh`, the build often fails because the generated Java interfaces reference new types or methods that the generator doesn't know how to handle yet, and the `*Impl` classes don't implement new interface methods.
|
||||
|
||||
### ApiGenerator.java fixes (tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java)
|
||||
|
||||
The generator has hardcoded lists that control which imports are added to each generated file. When new classes appear in the API, add them to the relevant lists in `Interface.writeTo`:
|
||||
- `options.*` import list — add new classes that use types from the options package
|
||||
- `java.util.*` import list — add new classes that use `List`, `Map`, etc.
|
||||
- `java.util.function.Consumer` list — add new classes with `Consumer`-typed event handlers
|
||||
|
||||
Type mapping: when JS-only types (like `Disposable`) are used as return types in Java-compatible methods, add a mapping in `convertBuiltinType`. For example, `Disposable` → `AutoCloseable`.
|
||||
|
||||
Event handler generation: events with `void` type generate invalid `Consumer<void>`. Handle this case in `Event.writeListenerMethods` by emitting `Runnable` instead.
|
||||
|
||||
After editing the generator, recompile and re-run it:
|
||||
```
|
||||
mvn -f tools/api-generator/pom.xml compile -q
|
||||
mvn -f tools/api-generator/pom.xml exec:java -Dexec.mainClass=com.microsoft.playwright.tools.ApiGenerator
|
||||
```
|
||||
|
||||
### Impl class fixes (playwright/src/main/java/com/microsoft/playwright/impl/)
|
||||
|
||||
After regenerating, compile `playwright/` to find what's missing:
|
||||
```
|
||||
mvn -f playwright/pom.xml compile 2>&1 | grep "ERROR"
|
||||
```
|
||||
|
||||
Common patterns:
|
||||
|
||||
**Return type changed (e.g. `void` → `AutoCloseable`):** Update the method signature in the Impl class and return an appropriate `AutoCloseable`. Check the JS client to see what kind of disposable is used:
|
||||
- If JS returns `DisposableObject.from(result.disposable)` — the server created a disposable channel object. Extract its guid from the protocol result and return `connection.getExistingObject(guid)` (a `DisposableObject`).
|
||||
- If JS returns `new DisposableStub(() => this.someCleanup())` — it's a local callback. Return `new DisposableStub(this::someCleanup)` in Java.
|
||||
- Examples: `addInitScript`/`exposeBinding`/`exposeFunction` → `DisposableObject`; `route(...)` → `DisposableStub(() -> unroute(...))`; `Tracing.group` → `DisposableStub(this::groupEnd)`; `Video.start` → `DisposableStub(this::stop)`.
|
||||
|
||||
**New method missing:** Add a stub implementation. Common patterns:
|
||||
- Simple protocol message: `sendMessage("methodName", params, NO_TIMEOUT)`
|
||||
- New property accessor (e.g. from initializer): `return initializer.get("fieldName").getAsString()`
|
||||
- Delegation to mainFrame (for Page methods): `return mainFrame.locator(":root").method(...)`
|
||||
|
||||
**New interface entirely (e.g. `Debugger`):** Create a new `*Impl` class extending `ChannelOwner`, implement the interface, and register the type in `Connection.java`'s switch statement. Initialize the field from the parent's initializer in the parent's constructor (e.g. `connection.getExistingObject(initializer.getAsJsonObject("debugger").get("guid").getAsString())`).
|
||||
|
||||
**Field visibility:** If a field needs to be accessed from a sibling Impl class (e.g. setting `existingResponse` on `RequestImpl` from `BrowserContextImpl`), change it from `private` to package-private.
|
||||
|
||||
**`ListenerCollection` only supports `Consumer<T>`, not `Runnable`.** For void events that use `Runnable` handlers, maintain a plain `List<Runnable>` instead.
|
||||
|
||||
**Protocol changes that remove events** — when a method's response now returns an object directly instead of via a subsequent event, update the Impl to capture it from the `sendMessage` result and remove the old event handler. Example: `videoStart` used to fire a `"video"` page event to deliver the artifact; it now returns the artifact directly in the response. Check git history of the upstream JS client when tests hang unexpectedly.
|
||||
|
||||
**Protocol parameter renames** — protocol parameter names can change between versions (e.g. `wsEndpoint` → `endpoint` in `BrowserType.connect`). When a test fails with `expected string, got undefined` or similar validation errors from the driver, check `packages/protocol/src/protocol.yml` for the current parameter names and update the corresponding `params.addProperty(...)` call in the Impl class. Also check the JS client (`src/client/`) to see how it builds the params object.
|
||||
|
||||
## Rebuilding the driver-bundle after a roll
|
||||
|
||||
`./scripts/roll_driver.sh` does the whole roll pipeline end-to-end: bumps `DRIVER_VERSION`, downloads new driver files into `driver-bundle/src/main/resources/driver/<platform>/`, regenerates `api.json` and the Java interfaces, and updates the README. When all of that succeeds, the next `mvn` invocation that touches `driver-bundle` will pick up the new files and you don't need to think about it.
|
||||
|
||||
But if any step in the pipeline fails (the very common case is the API generator throwing on a new type — see *Fixing generator and compilation errors*), the run aborts before `driver-bundle/target/classes/` has been refreshed. From that point on, until you manually rebuild `driver-bundle`, the test JVM will load the **old** driver from the cached `target/classes`/installed jar even though the source resources have already been swapped to the new version.
|
||||
|
||||
Fix — rebuild `driver-bundle` once before re-running tests:
|
||||
```
|
||||
mvn -f driver-bundle/pom.xml install -DskipTests
|
||||
```
|
||||
|
||||
## Porting and verifying tests
|
||||
|
||||
**Before porting an upstream test file, check the API exists in Java.** The upstream repo may have test files for brand-new APIs that haven't been added to the Java interface yet (e.g., `screencast.spec.ts` tests `page.screencast` which may not be in the generated `Page.java`). Check `git diff main --name-only` to see what interfaces were added this roll, and verify the method exists in the generated Java interface before porting.
|
||||
|
||||
**Java test file names don't always match upstream spec names.** `TestScreencast.java` tests `recordVideo` video-file recording (which corresponds to `video.spec.ts`), not the newer `page.screencast` streaming API (`screencast.spec.ts`). When comparing coverage, check test *content*, not just file names.
|
||||
|
||||
**Remove tests for behavior that was removed upstream.** When the JS client drops a client-side error check (e.g., "Page is not yet closed before saveAs", "Page did not produce any video frames"), delete the corresponding Java tests rather than trying to keep them passing. Check the upstream `tests/library/` spec to confirm the behavior is gone.
|
||||
|
||||
**Run the full suite to catch regressions, re-run flaky failures in isolation.** Some tests (e.g., `TestClientCertificates#shouldKeepSupportingHttp`) time out only under heavy parallel load. Run the failing test alone to confirm it's flaky before investigating further.
|
||||
|
||||
## Diagnosing hanging tests
|
||||
|
||||
When `mvn test` hangs and surefire eventually times the JVM out, it writes thread dumps to `playwright/target/surefire-reports/<timestamp>-jvmRun*.dump`. To find the stuck test:
|
||||
|
||||
```
|
||||
grep "com.microsoft.playwright.Test" playwright/target/surefire-reports/*-jvmRun1.dump | sort -u
|
||||
```
|
||||
|
||||
Each line is a stack frame inside a test method — typically you'll see one or two test methods blocked on a `Future.get()`, `waitForCondition`, or similar. That's the hanging test.
|
||||
|
||||
When you've identified a hanging test:
|
||||
1. Run it in isolation: `mvn -f playwright/pom.xml test -Dtest='TestClass#testMethod'`. If it passes alone, it's a parallel-load flake — note it but move on.
|
||||
2. If it still hangs in isolation, look for a recent fix in the upstream repo for the *same* test name. Use `git log --oneline tests/library/<spec>.spec.ts` in `~/playwright`. Upstream fixes for client-side hangs are often small and portable (e.g. `about:blank` → `server.EMPTY_PAGE` from microsoft/playwright#39840 fixed `route-web-socket.spec.ts` arraybuffer hangs — apparently some browser changed the WebSocket origin policy on `about:blank`).
|
||||
3. When porting an upstream fix, mirror the helper signature change rather than hard-coding workarounds. E.g. if upstream added a `server` parameter to `setupWS`, do the same in Java by injecting `Server server` via the JUnit fixture (`@FixtureTest` already wires up `ServerLifecycle`, so adding `Server server` to the test method signature is enough — no class-level boilerplate). Watch for local-variable shadowing when you add a `Server server` parameter to a method that already has a `WebSocketRoute server` local; rename the local.
|
||||
|
||||
## Commit Convention
|
||||
|
||||
Semantic commit messages: `label(scope): description`
|
||||
|
||||
Labels: `fix`, `feat`, `chore`, `docs`, `test`, `devops`
|
||||
|
||||
```bash
|
||||
git checkout -b fix-39562
|
||||
# ... make changes ...
|
||||
git add <changed-files>
|
||||
git commit -m "$(cat <<'EOF'
|
||||
fix(proxy): handle SOCKS proxy authentication
|
||||
|
||||
Fixes: https://github.com/microsoft/playwright-java/issues/39562
|
||||
EOF
|
||||
)"
|
||||
git push origin fix-39562
|
||||
gh pr create --repo microsoft/playwright-java --head username:fix-39562 \
|
||||
--title "fix(proxy): handle SOCKS proxy authentication" \
|
||||
--body "$(cat <<'EOF'
|
||||
## Summary
|
||||
- <describe the change very! briefly>
|
||||
|
||||
Fixes https://github.com/microsoft/playwright-java/issues/39562
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
Never add Co-Authored-By agents in commit message.
|
||||
Never add "Generated with" in commit message.
|
||||
Branch naming for issue fixes: `fix-<issue-number>`
|
||||
|
||||
## Tips & Tricks
|
||||
- Project checkouts are in the parent directory (`../`).
|
||||
- use the "gh" cli to interact with GitHub
|
||||
@@ -1,28 +0,0 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/java
|
||||
{
|
||||
"name": "Java",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/java:1-21-bookworm",
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/java:1": {
|
||||
"version": "none",
|
||||
"installGradle": "false",
|
||||
"installMaven": "true"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
||||
}
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
// "postCreateCommand": "java -version",
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
+2
-4
@@ -1,5 +1,3 @@
|
||||
# text files must be lf for golden file tests to work
|
||||
* text=auto eol=lf
|
||||
|
||||
# make project show as TS on GitHub
|
||||
*.js linguist-detectable=false
|
||||
*.txt eol=lf
|
||||
*.json eol=lf
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
name: Bug Report 🪲
|
||||
description: Create a bug report to help us improve
|
||||
title: '[Bug]: '
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Please follow these steps first:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Troubleshoot
|
||||
If Playwright is not behaving the way you expect, we'd ask you to look at the [documentation](https://playwright.dev/java/docs/intro) and search the issue tracker for evidence supporting your expectation.
|
||||
Please make reasonable efforts to troubleshoot and rule out issues with your code, the configuration, or any 3rd party libraries you might be using.
|
||||
Playwright offers [several debugging tools](https://playwright.dev/java/docs/debug) that you can use to troubleshoot your issues.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Ask for help through appropriate channels
|
||||
If you feel unsure about the cause of the problem, consider asking for help on for example [StackOverflow](https://stackoverflow.com/questions/ask) or our [Discord channel](https://aka.ms/playwright/discord) before posting a bug report. The issue tracker is not a help forum.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Make a minimal reproduction
|
||||
To file the report, you will need a GitHub repository with a minimal (but complete) example and simple/clear steps on how to reproduce the bug.
|
||||
The simpler you can make it, the more likely we are to successfully verify and fix the bug.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> [!IMPORTANT]
|
||||
> Bug reports without a minimal reproduction will be rejected.
|
||||
|
||||
---
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: |
|
||||
The version of Playwright you are using.
|
||||
Is it the [latest](https://github.com/microsoft/playwright-java/releases)? Test and see if the bug has already been fixed.
|
||||
placeholder: ex. 1.41.1
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please link to a repository with a minimal reproduction and describe accurately how we can reproduce/verify the bug.
|
||||
placeholder: |
|
||||
Example steps (replace with your own):
|
||||
1. Clone my repo at https://github.com/<myuser>/example
|
||||
2. mvn test
|
||||
3. You should see the error come up
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A description of what you expect to happen.
|
||||
placeholder: I expect to see X or Y
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: |
|
||||
A clear and concise description of the unexpected behavior.
|
||||
Please include any relevant output here, especially any error messages.
|
||||
placeholder: A bug happened!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Anything else that might be relevant
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: envinfo
|
||||
attributes:
|
||||
label: Environment
|
||||
description: |
|
||||
Please provide information about the environment you are running in.
|
||||
placeholder: |
|
||||
- Operating System: [Ubuntu 22.04]
|
||||
- CPU: [arm64]
|
||||
- Browser: [All, Chromium, Firefox, WebKit]
|
||||
- Java Version: [20]
|
||||
- Maven Version: [3.8.6]
|
||||
- Other info:
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Join our Discord Server
|
||||
url: https://aka.ms/playwright/discord
|
||||
about: Ask questions and discuss with other community members
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Documentation 📖
|
||||
description: Submit a request to add or update documentation
|
||||
title: '[Docs]: '
|
||||
labels: ['Documentation :book:']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Thank you for helping us improve our documentation!
|
||||
Please be sure you are looking at [the Next version of the documentation](https://playwright.dev/java/docs/next/intro) before opening an issue here.
|
||||
- type: textarea
|
||||
id: links
|
||||
attributes:
|
||||
label: Page(s)
|
||||
description: |
|
||||
Links to one or more documentation pages that should be modified.
|
||||
If you are reporting an issue with a specific section of a page, try to link directly to the nearest anchor.
|
||||
If you are suggesting that a new page be created, link to the parent of the proposed page.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Describe the change you are requesting.
|
||||
If the issue pertains to a single function or matcher, be sure to specify the entire call signature.
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Feature Request 🚀
|
||||
description: Submit a proposal for a new feature
|
||||
title: '[Feature]: '
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Thank you for taking the time to suggest a new feature!
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: '🚀 Feature Request'
|
||||
description: A clear and concise description of what the feature is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Example
|
||||
description: Describe how this feature would be used.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: |
|
||||
Outline your motivation for the proposal. How will it make Playwright better?
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,27 +0,0 @@
|
||||
name: 'Questions / Help 💬'
|
||||
description: If you have questions, please check StackOverflow or Discord
|
||||
title: '[Please read the message below]'
|
||||
labels: [':speech_balloon: Question']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Questions and Help 💬
|
||||
|
||||
This issue tracker is reserved for bug reports and feature requests.
|
||||
|
||||
For anything else, such as questions or getting help, please see:
|
||||
|
||||
- [The Playwright documentation](https://playwright.dev/java)
|
||||
- [Our Discord server](https://aka.ms/playwright/discord)
|
||||
- type: checkboxes
|
||||
id: no-post
|
||||
attributes:
|
||||
label: |
|
||||
Please do not submit this issue.
|
||||
description: |
|
||||
> [!IMPORTANT]
|
||||
> This issue will be closed.
|
||||
options:
|
||||
- label: I understand
|
||||
required: true
|
||||
@@ -1,90 +0,0 @@
|
||||
name: Report regression
|
||||
description: Functionality that used to work and does not any more
|
||||
title: "[Regression]: "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
# Please follow these steps first:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Make a minimal reproduction
|
||||
To file the report, you will need a GitHub repository with a minimal (but complete) example and simple/clear steps on how to reproduce the regression.
|
||||
The simpler you can make it, the more likely we are to successfully verify and fix the regression.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> [!IMPORTANT]
|
||||
> Regression reports without a minimal reproduction will be rejected.
|
||||
|
||||
---
|
||||
- type: input
|
||||
id: goodVersion
|
||||
attributes:
|
||||
label: Last Good Version
|
||||
description: |
|
||||
Last version of Playwright where the feature was working.
|
||||
placeholder: ex. 1.40.1
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: badVersion
|
||||
attributes:
|
||||
label: First Bad Version
|
||||
description: |
|
||||
First version of Playwright where the feature was broken.
|
||||
Is it the [latest](https://github.com/microsoft/playwright-java/releases)? Test and see if the regression has already been fixed.
|
||||
placeholder: ex. 1.41.1
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please link to a repository with a minimal reproduction and describe accurately how we can reproduce/verify the bug.
|
||||
placeholder: |
|
||||
Example steps (replace with your own):
|
||||
1. Clone my repo at https://github.com/<myuser>/example
|
||||
2. mvn test
|
||||
3. You should see the error come up
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A description of what you expect to happen.
|
||||
placeholder: I expect to see X or Y
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: A clear and concise description of the unexpected behavior.
|
||||
placeholder: A bug happened!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Anything else that might be relevant
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: envinfo
|
||||
attributes:
|
||||
label: Environment
|
||||
description: |
|
||||
Please provide information about the environment you are running in.
|
||||
placeholder: |
|
||||
- Operating System: [Ubuntu 22.04]
|
||||
- CPU: [arm64]
|
||||
- Browser: [All, Chromium, Firefox, WebKit]
|
||||
- Java Version: [20]
|
||||
- Maven Version: [3.8.6]
|
||||
- Other info:
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,27 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/" # Location of the pom.xml file
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
# Create a group of dependencies to be updated together in one pull request
|
||||
all:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
allow:
|
||||
- dependency-type: "direct" # Optional: Only update direct dependencies
|
||||
- dependency-type: "indirect" # Optional: Only update indirect (transitive) dependencies
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Publish
|
||||
on:
|
||||
workflow_dispatch
|
||||
jobs:
|
||||
build:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
server-username: MAVEN_USERNAME # env variable for username in deploy
|
||||
server-password: MAVEN_PASSWORD # env variable for token in deploy
|
||||
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
|
||||
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver_for_all_platforms.sh
|
||||
- name: Publish to Maven Central
|
||||
run: mvn deploy --batch-mode -D skipTests --activate-profiles release --no-transfer-progress
|
||||
env:
|
||||
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
|
||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Publish Release Docker
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
publish-canary-docker:
|
||||
name: publish to DockerHub
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
id-token: write # This is required for OIDC login (azure/login) to succeed
|
||||
contents: read # This is required for actions/checkout to succeed
|
||||
environment: Docker
|
||||
if: github.repository == 'microsoft/playwright-java'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Azure login
|
||||
uses: azure/login@v3
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_DOCKER_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_DOCKER_TENANT_ID }}
|
||||
subscription-id: ${{ secrets.AZURE_DOCKER_SUBSCRIPTION_ID }}
|
||||
- name: Login to ACR via OIDC
|
||||
run: az acr login --name playwright
|
||||
- name: Set up Docker QEMU for arm64 docker builds
|
||||
uses: docker/setup-qemu-action@v4
|
||||
with:
|
||||
platforms: arm64
|
||||
- uses: actions/checkout@v6
|
||||
- run: ./utils/docker/publish_docker.sh stable
|
||||
+18
-116
@@ -1,135 +1,37 @@
|
||||
name: Build & Test
|
||||
name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
env:
|
||||
PW_MAX_RETRIES: 3
|
||||
branches: [ master ]
|
||||
jobs:
|
||||
dev:
|
||||
build:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
browser: [chromium, firefox, webkit]
|
||||
exclude:
|
||||
# macos-latest is the free M1 runner (3 vCPU / 7 GB); WebKit needs more headroom.
|
||||
# Upstream's webkit matrix runs on macos-15-xlarge for the same reason.
|
||||
- os: macos-latest
|
||||
browser: webkit
|
||||
include:
|
||||
- os: macos-15-xlarge
|
||||
browser: webkit
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v5
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: 8
|
||||
java-version: 1.8
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
run: scripts/download_driver_for_all_platforms.sh
|
||||
- name: Build with Maven
|
||||
run: mvn -B package -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
run: mvn test --no-transfer-progress
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
- name: Run tracing tests w/ sources
|
||||
run: mvn test --no-transfer-progress --fail-at-end --projects=playwright -D test=*TestTracing* -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
PLAYWRIGHT_JAVA_SRC: src/test/java
|
||||
- name: Test Spring Boot Starter
|
||||
shell: bash
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
run: |
|
||||
cd tools/test-spring-boot-starter
|
||||
mvn package -D skipTests --no-transfer-progress
|
||||
java -jar target/test-spring-boot*.jar
|
||||
|
||||
stable:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
browser-channel: [chrome]
|
||||
include:
|
||||
- os: windows-latest
|
||||
browser-channel: msedge
|
||||
- os: macos-latest
|
||||
browser-channel: msedge
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install Media Pack
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: powershell
|
||||
run: Install-WindowsFeature Server-Media-Foundation
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: 8
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Install MS Edge
|
||||
if: matrix.browser-channel == 'msedge' && matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install msedge" -f playwright/pom.xml
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
env:
|
||||
BROWSER: chromium
|
||||
BROWSER_CHANNEL: ${{ matrix.browser-channel }}
|
||||
|
||||
Java_21:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: [chromium, firefox, webkit]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: adopt
|
||||
java-version: 21
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
- name: Test Spring Boot Starter
|
||||
shell: bash
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
run: |
|
||||
cd tools/test-spring-boot-starter
|
||||
mvn package -D skipTests --no-transfer-progress
|
||||
java -jar target/test-spring-boot*.jar
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Test CLI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
jobs:
|
||||
verify:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2
|
||||
- name: Download drivers
|
||||
run: scripts/download_driver.sh
|
||||
- name: Intall Playwright
|
||||
run: mvn install -D skipTests --no-transfer-progress
|
||||
- name: Test CLI
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -f playwright/pom.xml -D exec.args=-V
|
||||
- name: Test CLI version
|
||||
shell: bash
|
||||
run: tools/test-cli-version/test.sh
|
||||
- name: Test CLI Fatjar
|
||||
shell: bash
|
||||
run: tools/test-cli-fatjar/test.sh
|
||||
@@ -1,77 +0,0 @@
|
||||
name: Docker
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/test_docker.yml'
|
||||
- '**/Dockerfile*'
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test_docker.yml
|
||||
- '**/Dockerfile*'
|
||||
- scripts/DRIVER_VERSION
|
||||
- '**/pom.xml'
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
timeout-minutes: 120
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
env:
|
||||
PW_MAX_RETRIES: 3
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [jammy, noble]
|
||||
runs-on: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
include:
|
||||
- runs-on: ubuntu-24.04
|
||||
arch: amd64
|
||||
- runs-on: ubuntu-24.04-arm
|
||||
arch: arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
bash utils/docker/build.sh --${{ matrix.arch }} ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
|
||||
- name: Start container
|
||||
run: |
|
||||
CONTAINER_ID=$(docker run \
|
||||
--rm \
|
||||
--name playwright-docker-test \
|
||||
--platform linux/${{ matrix.arch }} \
|
||||
--user=pwuser \
|
||||
--workdir /home/pwuser \
|
||||
--shm-size=2g \
|
||||
-e CI \
|
||||
-e PW_MAX_RETRIES \
|
||||
-d -t \
|
||||
playwright-java:localbuild-${{ matrix.flavor }} /bin/bash)
|
||||
echo "CONTAINER_ID=$CONTAINER_ID" >> $GITHUB_ENV
|
||||
|
||||
- name: Copy repository inside docker container
|
||||
run: |
|
||||
docker cp . "$CONTAINER_ID":/home/pwuser/playwright
|
||||
# /root/.m2 was populated as root during image build; move it to
|
||||
# pwuser so the locally-installed SNAPSHOT artifacts resolve.
|
||||
docker exec --user root "$CONTAINER_ID" bash -c '
|
||||
chown -R pwuser /home/pwuser/playwright
|
||||
mv /root/.m2 /home/pwuser/.m2
|
||||
chown -R pwuser /home/pwuser/.m2
|
||||
'
|
||||
|
||||
- name: Run smoke tests in container
|
||||
run: |
|
||||
docker exec "$CONTAINER_ID" /home/pwuser/playwright/tools/test-local-installation/create_project_and_run_tests.sh -Dgroups=smoke
|
||||
|
||||
- name: Test ClassLoader
|
||||
run: |
|
||||
docker exec "${CONTAINER_ID}" /home/pwuser/playwright/tools/test-spring-boot-starter/package_and_run_async_test.sh
|
||||
|
||||
- name: Stop container
|
||||
run: |
|
||||
docker stop "$CONTAINER_ID"
|
||||
@@ -1,39 +1,37 @@
|
||||
name: Verify API
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'scripts/*'
|
||||
- 'api-generator/*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- release-*
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- 'scripts/**'
|
||||
- 'api-generator/**'
|
||||
jobs:
|
||||
verify:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2
|
||||
- name: Download drivers
|
||||
run: scripts/download_driver.sh
|
||||
run: scripts/download_driver_for_all_platforms.sh
|
||||
- name: Regenerate APIs
|
||||
run: scripts/generate_api.sh
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Install browsers
|
||||
run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml --no-transfer-progress
|
||||
- name: Update browser versions in README
|
||||
run: scripts/update_readme.sh
|
||||
- name: Verify API is up to date
|
||||
run: |
|
||||
if [[ -n $(git status -s) ]]; then
|
||||
echo "ERROR: generated interfaces/docs differ from the current sources:"
|
||||
echo "ERROR: generated interfaces differ from the current sources:"
|
||||
git diff
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+9
-27
@@ -2,16 +2,7 @@
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### Installing Developer Tools
|
||||
|
||||
Install git, Java JDK (version >= 8), Maven (tested with version 3.6.3), on Ubuntu 20.04
|
||||
just run the following command:
|
||||
|
||||
```sh
|
||||
sudo apt-get install git openjdk-11-jdk maven unzip
|
||||
```
|
||||
|
||||
### Getting the Code
|
||||
### Getting Code
|
||||
|
||||
1. Clone this repository
|
||||
|
||||
@@ -20,40 +11,31 @@ git clone https://github.com/microsoft/playwright-java
|
||||
cd playwright-java
|
||||
```
|
||||
|
||||
2. Run the following script to download Playwright driver for all platforms into `driver-bundle/src/main/resources/driver/` directory (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run).
|
||||
2. Run the following script to download playwright-cli binaries for all platforms into `driver-bundle/src/main/resources/driver/` directory (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run).
|
||||
|
||||
```bash
|
||||
scripts/download_driver.sh
|
||||
scripts/download_driver_for_all_platforms.sh
|
||||
```
|
||||
|
||||
### Building and running the tests with Maven
|
||||
Names of published driver archives can be found at https://github.com/microsoft/playwright-cli/actions
|
||||
|
||||
### Compiling and running the tests with Maven
|
||||
|
||||
```bash
|
||||
mvn compile
|
||||
mvn test
|
||||
# Executing a single test
|
||||
BROWSER=chromium mvn test -Dtest=TestPageNetworkSizes#shouldHaveTheCorrectResponseBodySize
|
||||
# Executing a single test class
|
||||
BROWSER=chromium mvn test -Dtest=TestPageNetworkSizes
|
||||
```
|
||||
|
||||
### Generating API
|
||||
|
||||
Public Java API is generated from api.json which is produced by `print-api-json` command of playwright CLI. To regenerate Java interfaces for the current driver run the following commands:
|
||||
Public Java API is generated from api.json which is produced by `playwright-cli print-api-json`. To regenerate
|
||||
Java interfaces for the current driver run the following commands:
|
||||
|
||||
```bash
|
||||
./scripts/download_driver.sh
|
||||
./scripts/download_driver_for_all_platforms.sh
|
||||
./scripts/generate_api.sh
|
||||
```
|
||||
|
||||
#### Updating driver version
|
||||
|
||||
Versions of published driver archives can be found in [publish canary](https://github.com/microsoft/playwright/actions/workflows/publish_canary.yml) and [publish release](https://github.com/microsoft/playwright/actions/workflows/publish_release_driver.yml) actions logs. To update the driver to a particular version run the following command:
|
||||
|
||||
```bash
|
||||
scripts/roll_driver.sh [version]
|
||||
```
|
||||
|
||||
### Code Style
|
||||
|
||||
- We try to follow [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
path_classifiers:
|
||||
tests:
|
||||
- "playwright/src/test/**"
|
||||
@@ -0,0 +1,71 @@
|
||||
FROM ubuntu:focal
|
||||
|
||||
# === INSTALL BROWSER DEPENDENCIES ===
|
||||
|
||||
# Install WebKit dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libwoff1 \
|
||||
libopus0 \
|
||||
libwebp6 \
|
||||
libwebpdemux2 \
|
||||
libenchant1c2a \
|
||||
libgudev-1.0-0 \
|
||||
libsecret-1-0 \
|
||||
libhyphen0 \
|
||||
libgdk-pixbuf2.0-0 \
|
||||
libegl1 \
|
||||
libnotify4 \
|
||||
libxslt1.1 \
|
||||
libevent-2.1-7 \
|
||||
libgles2 \
|
||||
libxcomposite1 \
|
||||
libatk1.0-0 \
|
||||
libatk-bridge2.0-0 \
|
||||
libepoxy0 \
|
||||
libgtk-3-0 \
|
||||
libharfbuzz-icu0
|
||||
|
||||
# Install gstreamer and plugins to support video playback in WebKit.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgstreamer-gl1.0-0 \
|
||||
libgstreamer-plugins-bad1.0-0 \
|
||||
gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-libav
|
||||
|
||||
# Install Chromium dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libasound2 \
|
||||
fonts-noto-color-emoji \
|
||||
libxtst6
|
||||
|
||||
# Install Firefox dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libdbus-glib-1-2 \
|
||||
libxt6
|
||||
|
||||
# Install ffmpeg to bring in audio and video codecs necessary for playing videos in Firefox.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ffmpeg
|
||||
|
||||
# (Optional) Install XVFB if there's a need to run browsers in headful mode
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
xvfb
|
||||
|
||||
# === INSTALL JDK and Maven ===
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
openjdk-8-jdk maven
|
||||
|
||||
# Install utilities required for downloading driver
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl unzip
|
||||
|
||||
# === INSTALL Playwright-java ===
|
||||
|
||||
RUN mkdir /tmp/pw-java
|
||||
COPY . /tmp/pw-java
|
||||
RUN cd /tmp/pw-java && ./scripts/download_driver_for_all_platforms.sh && \
|
||||
mvn install -D skipTests --no-transfer-progress && \
|
||||
rm -rf /tmp/pw-java
|
||||
@@ -1,30 +1,60 @@
|
||||
# 🎭 [Playwright](https://playwright.dev) for Java
|
||||
|
||||
[](https://javadoc.io/doc/com.microsoft.playwright/playwright)
|
||||
[](https://search.maven.org/search?q=com.microsoft.playwright)
|
||||
[](https://aka.ms/playwright/discord)
|
||||
[](https://search.maven.org/search?q=com.microsoft.playwright) [](https://join.slack.com/t/playwright/shared_invite/enQtOTEyMTUxMzgxMjIwLThjMDUxZmIyNTRiMTJjNjIyMzdmZDA3MTQxZWUwZTFjZjQwNGYxZGM5MzRmNzZlMWI5ZWUyOTkzMjE5Njg1NDg)
|
||||
|
||||
#### [Website](https://playwright.dev/java/) | [API reference](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html)
|
||||
#### [Website](https://playwright.dev/) | [API reference](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html)
|
||||
|
||||
Playwright is a Java library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) with a single API. Playwright is built to enable cross-browser web automation that is **ever-green**, **capable**, **reliable** and **fast**.
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->148.0.7778.96<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->26.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->150.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->89.0.4344.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->14.1<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->85.0b1<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
## Documentation
|
||||
Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/#?path=docs/intro.md&q=system-requirements) for details.
|
||||
|
||||
[https://playwright.dev/java/docs/intro](https://playwright.dev/java/docs/intro)
|
||||
* [Usage](#usage)
|
||||
- [Add Maven dependency](#add-maven-dependency)
|
||||
- [Is Playwright thread-safe?](#is-playwright-thread-safe)
|
||||
* [Examples](#examples)
|
||||
- [Page screenshot](#page-screenshot)
|
||||
- [Mobile and geolocation](#mobile-and-geolocation)
|
||||
- [Evaluate JavaScript in browser](#evaluate-javascript-in-browser)
|
||||
- [Intercept network requests](#intercept-network-requests)
|
||||
* [Documentation](#documentation)
|
||||
* [Contributing](#contributing)
|
||||
* [Is Playwright for Java ready?](#is-playwright-for-java-ready)
|
||||
|
||||
## API Reference
|
||||
## Usage
|
||||
|
||||
[https://playwright.dev/java/docs/api/class-playwright](https://playwright.dev/java/docs/api/class-playwright)
|
||||
Playwright requires **Java 8** or newer.
|
||||
|
||||
## Example
|
||||
#### Add Maven dependency
|
||||
|
||||
This code snippet navigates to Playwright homepage in Chromium, Firefox and WebKit, and saves 3 screenshots.
|
||||
Playwright is distributed as a set of [Maven](https://maven.apache.org/what-is-maven.html) modules. The easiest way to use it is to add a couple of dependencies to your Maven `pom.xml` file as described below. If you're not familiar with Maven please refer to its [documentation](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).
|
||||
|
||||
To run Playwright simply add following dependency to your Maven project:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>0.171.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### Is Playwright thread-safe?
|
||||
|
||||
No, Playwright is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create new many Playwright instances each on its own thread.
|
||||
|
||||
## Examples
|
||||
|
||||
You can find Maven project with the examples [here](./examples).
|
||||
|
||||
#### Page screenshot
|
||||
|
||||
This code snippet navigates to whatsmyuseragent.org in Chromium, Firefox and WebKit, and saves 3 screenshots.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
@@ -34,29 +64,121 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PageScreenshot {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
List<BrowserType> browserTypes = Arrays.asList(
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
List<BrowserType> browserTypes = Arrays.asList(
|
||||
playwright.chromium(),
|
||||
playwright.webkit(),
|
||||
playwright.firefox()
|
||||
);
|
||||
for (BrowserType browserType : browserTypes) {
|
||||
try (Browser browser = browserType.launch()) {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
}
|
||||
}
|
||||
);
|
||||
for (BrowserType browserType : browserTypes) {
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions().withViewport(800, 600));
|
||||
Page page = context.newPage();
|
||||
page.navigate("http://whatsmyuseragent.org/");
|
||||
page.screenshot(new Page.ScreenshotOptions().withPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
browser.close();
|
||||
}
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Other languages
|
||||
#### Mobile and geolocation
|
||||
|
||||
More comfortable in another programming language? [Playwright](https://playwright.dev) is also available in
|
||||
- [Node.js (JavaScript / TypeScript)](https://playwright.dev/docs/intro),
|
||||
- [Python](https://playwright.dev/python/docs/intro).
|
||||
- [.NET](https://playwright.dev/dotnet/docs/intro),
|
||||
This snippet emulates Mobile Chromium on a device at a given geolocation, navigates to openstreetmap.org, performs action and takes a screenshot.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
import java.nio.file.Paths;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class MobileAndGeolocation {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.chromium();
|
||||
Browser browser = browserType.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||
DeviceDescriptor pixel2 = playwright.devices().get("Pixel 2");
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.withDevice(pixel2)
|
||||
.withLocale("en-US")
|
||||
.withGeolocation(new Geolocation(41.889938, 12.492507))
|
||||
.withPermissions(asList("geolocation")));
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.openstreetmap.org/");
|
||||
page.click("a[data-original-title=\"Show My Location\"]");
|
||||
page.screenshot(new Page.ScreenshotOptions().withPath(Paths.get("colosseum-pixel2.png")));
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Evaluate JavaScript in browser
|
||||
|
||||
This code snippet navigates to example.com in Firefox, and executes a script in the page context.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class EvaluateInBrowserContext {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.firefox();
|
||||
Browser browser = browserType.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.example.com/");
|
||||
Object dimensions = page.evaluate("() => {\n" +
|
||||
" return {\n" +
|
||||
" width: document.documentElement.clientWidth,\n" +
|
||||
" height: document.documentElement.clientHeight,\n" +
|
||||
" deviceScaleFactor: window.devicePixelRatio\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
System.out.println(dimensions);
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Intercept network requests
|
||||
|
||||
This code snippet sets up request routing for a WebKit page to log all network requests.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class InterceptNetworkRequests {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.webkit();
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.route("**", route -> {
|
||||
System.out.println(route.request().url());
|
||||
route.continue_();
|
||||
});
|
||||
page.navigate("http://todomvc.com");
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
We are in the process of converting our documentation from the Node.js form to [Javadocs](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html). You can go ahead and use the Node.js [documentation](https://playwright.dev/) since the API is pretty much the same.
|
||||
|
||||
## Contributing
|
||||
|
||||
Follow [the instructions](https://github.com/microsoft/playwright-java/blob/master/CONTRIBUTING.md#getting-code) to build the project from source and install the driver.
|
||||
|
||||
## Is Playwright for Java ready?
|
||||
|
||||
Yes, Playwright for Java is ready. We are still not at the version v1.0, so breaking API changes could potentially happen. But a) this is unlikely and b) we will only do that if we know it improves your experience with the new library. We'd like to collect your feedback before we freeze the API for v1.0.
|
||||
|
||||
> Note: We don't yet support some of the edge-cases of the vendor-specific APIs such as collecting Chromium trace, coverage report, etc.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Rolling Playwright-Java to the latest Playwright driver
|
||||
|
||||
* make sure to have at least Java 8 and Maven 3.6.3
|
||||
* clone playwright for java: http://github.com/microsoft/playwright-java
|
||||
* roll the driver and update generated sources: `./scripts/roll_driver.sh next`
|
||||
* fix any errors
|
||||
* commit & send PR with the roll
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub issues to track bugs and feature requests. Please search the [existing issues][gh-issues] before filing new ones to avoid duplicates. For new issues, file your bug or feature request as a new issue using corresponding template.
|
||||
|
||||
For help and questions about using this project, please see the [docs site for Playwright for Java][docs].
|
||||
|
||||
Join our community [Discord Server][discord-server] to connect with other developers using Playwright and ask questions in our 'help-playwright' forum.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for Playwright for Java is limited to the resources listed above.
|
||||
|
||||
[gh-issues]: https://github.com/microsoft/playwright-java/issues/
|
||||
[docs]: https://playwright.dev/java/
|
||||
[discord-server]: https://aka.ms/playwright/discord
|
||||
+34
-2
@@ -6,16 +6,48 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.50.0-SNAPSHOT</version>
|
||||
<version>0.180.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
<name>Playwright - Drivers For All Platforms</name>
|
||||
<description>
|
||||
This module includes Playwright driver and related utilities for all supported platforms.
|
||||
This module includes playwright-cli binary and related utilities for all supported platforms.
|
||||
It is intended to be used on the systems where Playwright driver is not preinstalled.
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludeResources>true</excludeResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DriverJar extends Driver {
|
||||
private final Path driverTempDir;
|
||||
|
||||
DriverJar() throws IOException, URISyntaxException, InterruptedException {
|
||||
driverTempDir = Files.createTempDirectory("playwright-java-");
|
||||
driverTempDir.toFile().deleteOnExit();
|
||||
extractDriverToTempDir();
|
||||
installBrowsers();
|
||||
}
|
||||
|
||||
private void installBrowsers() throws IOException, InterruptedException {
|
||||
String cliFileName = super.cliFileName();
|
||||
Path driver = driverTempDir.resolve(cliFileName);
|
||||
if (!Files.exists(driver)) {
|
||||
throw new RuntimeException("Failed to find " + cliFileName + " at " + driver);
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder(driver.toString(), "install");
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
Process p = pb.start();
|
||||
boolean result = p.waitFor(10, TimeUnit.MINUTES);
|
||||
if (!result) {
|
||||
p.destroy();
|
||||
throw new RuntimeException("Timed out waiting for browsers to install");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExecutable(Path filePath) {
|
||||
String name = filePath.getFileName().toString();
|
||||
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
|
||||
}
|
||||
|
||||
private void extractDriverToTempDir() throws URISyntaxException, IOException {
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
URI uri = classloader.getResource("driver/" + platformDir()).toURI();
|
||||
// Create zip filesystem if loading from jar.
|
||||
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? FileSystems.newFileSystem(uri, Collections.emptyMap()) : null) {
|
||||
Path srcRoot = Paths.get(uri);
|
||||
Files.walk(srcRoot).forEach(fromPath -> {
|
||||
Path relative = srcRoot.relativize(fromPath);
|
||||
Path toPath = driverTempDir.resolve(relative.toString());
|
||||
try {
|
||||
if (Files.isDirectory(fromPath)) {
|
||||
Files.createDirectories(toPath);
|
||||
} else {
|
||||
Files.copy(fromPath, toPath);
|
||||
if (isExecutable(toPath)) {
|
||||
toPath.toFile().setExecutable(true, true);
|
||||
}
|
||||
}
|
||||
toPath.toFile().deleteOnExit();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract driver from " + uri, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static String platformDir() {
|
||||
String name = System.getProperty("os.name").toLowerCase();
|
||||
if (name.contains("windows")) {
|
||||
return System.getProperty("os.arch").equals("amd64") ? "win32_x64" : "win32";
|
||||
}
|
||||
if (name.contains("linux")) {
|
||||
return "linux";
|
||||
}
|
||||
if (name.contains("mac os x")) {
|
||||
return "mac";
|
||||
}
|
||||
throw new RuntimeException("Unexpected os.name value: " + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
Path driverDir() {
|
||||
return driverTempDir;
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl.driver.jar;
|
||||
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DriverJar extends Driver {
|
||||
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
|
||||
private static final String SELENIUM_REMOTE_URL = "SELENIUM_REMOTE_URL";
|
||||
private final Path driverTempDir;
|
||||
private Path preinstalledNodePath;
|
||||
|
||||
public DriverJar() throws IOException {
|
||||
// Allow specifying custom path for the driver installation
|
||||
// See https://github.com/microsoft/playwright-java/issues/728
|
||||
String alternativeTmpdir = System.getProperty("playwright.driver.tmpdir");
|
||||
String prefix = "playwright-java-";
|
||||
driverTempDir = alternativeTmpdir == null
|
||||
? Files.createTempDirectory(prefix)
|
||||
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
|
||||
driverTempDir.toFile().deleteOnExit();
|
||||
String nodePath = System.getProperty("playwright.nodejs.path");
|
||||
if (nodePath != null) {
|
||||
preinstalledNodePath = Paths.get(nodePath);
|
||||
if (!Files.exists(preinstalledNodePath)) {
|
||||
throw new RuntimeException("Invalid Node.js path specified: " + nodePath);
|
||||
}
|
||||
}
|
||||
logMessage("created DriverJar: " + driverTempDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(Boolean installBrowsers) throws Exception {
|
||||
if (preinstalledNodePath == null && env.containsKey(PLAYWRIGHT_NODEJS_PATH)) {
|
||||
preinstalledNodePath = Paths.get(env.get(PLAYWRIGHT_NODEJS_PATH));
|
||||
if (!Files.exists(preinstalledNodePath)) {
|
||||
throw new RuntimeException("Invalid Node.js path specified: " + preinstalledNodePath);
|
||||
}
|
||||
} else if (preinstalledNodePath != null) {
|
||||
// Pass the env variable to the driver process.
|
||||
env.put(PLAYWRIGHT_NODEJS_PATH, preinstalledNodePath.toString());
|
||||
}
|
||||
extractDriverToTempDir();
|
||||
logMessage("extracted driver from jar to " + driverDir());
|
||||
if (installBrowsers)
|
||||
installBrowsers(env);
|
||||
}
|
||||
|
||||
private void installBrowsers(Map<String, String> env) throws IOException, InterruptedException {
|
||||
String skip = env.get(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
|
||||
if (skip == null) {
|
||||
skip = System.getenv(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD);
|
||||
}
|
||||
if (skip != null && !"0".equals(skip) && !"false".equals(skip)) {
|
||||
logMessage("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set");
|
||||
return;
|
||||
}
|
||||
if (env.get(SELENIUM_REMOTE_URL) != null || System.getenv(SELENIUM_REMOTE_URL) != null) {
|
||||
logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set");
|
||||
return;
|
||||
}
|
||||
Path driver = driverDir();
|
||||
if (!Files.exists(driver)) {
|
||||
throw new RuntimeException("Failed to find driver: " + driver);
|
||||
}
|
||||
ProcessBuilder pb = createProcessBuilder();
|
||||
pb.command().add("install");
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
Process p = pb.start();
|
||||
boolean result = p.waitFor(10, TimeUnit.MINUTES);
|
||||
if (!result) {
|
||||
p.destroy();
|
||||
throw new RuntimeException("Timed out waiting for browsers to install");
|
||||
}
|
||||
if (p.exitValue() != 0) {
|
||||
throw new RuntimeException("Failed to install browsers, exit code: " + p.exitValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExecutable(Path filePath) {
|
||||
String name = filePath.getFileName().toString();
|
||||
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
|
||||
}
|
||||
|
||||
private FileSystem initFileSystem(URI uri) throws IOException {
|
||||
try {
|
||||
return FileSystems.newFileSystem(uri, Collections.emptyMap());
|
||||
} catch (FileSystemAlreadyExistsException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static URI getDriverResourceURI() throws URISyntaxException {
|
||||
ClassLoader classloader = DriverJar.class.getClassLoader();
|
||||
return classloader.getResource("driver/" + platformDir()).toURI();
|
||||
}
|
||||
|
||||
void extractDriverToTempDir() throws URISyntaxException, IOException {
|
||||
URI originalUri = getDriverResourceURI();
|
||||
URI uri = maybeExtractNestedJar(originalUri);
|
||||
|
||||
// Create zip filesystem if loading from jar.
|
||||
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
|
||||
Path srcRoot = Paths.get(uri);
|
||||
// jar file system's .relativize gives wrong results when used with
|
||||
// spring-boot-maven-plugin, convert to the default filesystem to
|
||||
// have predictable results.
|
||||
// See https://github.com/microsoft/playwright-java/issues/306
|
||||
Path srcRootDefaultFs = Paths.get(srcRoot.toString());
|
||||
Files.walk(srcRoot).forEach(fromPath -> {
|
||||
if (preinstalledNodePath != null) {
|
||||
String fileName = fromPath.getFileName().toString();
|
||||
if ("node.exe".equals(fileName) || "node".equals(fileName)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Path relative = srcRootDefaultFs.relativize(Paths.get(fromPath.toString()));
|
||||
Path toPath = driverTempDir.resolve(relative.toString());
|
||||
try {
|
||||
if (Files.isDirectory(fromPath)) {
|
||||
Files.createDirectories(toPath);
|
||||
} else {
|
||||
Files.copy(fromPath, toPath);
|
||||
if (isExecutable(toPath)) {
|
||||
toPath.toFile().setExecutable(true, true);
|
||||
}
|
||||
}
|
||||
toPath.toFile().deleteOnExit();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract driver from " + uri + ", full uri: " + originalUri, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private URI maybeExtractNestedJar(final URI uri) throws URISyntaxException {
|
||||
if (!"jar".equals(uri.getScheme())) {
|
||||
return uri;
|
||||
}
|
||||
final String JAR_URL_SEPARATOR = "!/";
|
||||
String[] parts = uri.toString().split("!/");
|
||||
if (parts.length != 3) {
|
||||
return uri;
|
||||
}
|
||||
String innerJar = String.join(JAR_URL_SEPARATOR, parts[0], parts[1]);
|
||||
URI jarUri = new URI(innerJar);
|
||||
try (FileSystem fs = FileSystems.newFileSystem(jarUri, Collections.emptyMap())) {
|
||||
Path fromPath = Paths.get(jarUri);
|
||||
Path toPath = driverTempDir.resolve(fromPath.getFileName().toString());
|
||||
Files.copy(fromPath, toPath);
|
||||
toPath.toFile().deleteOnExit();
|
||||
return new URI("jar:" + toPath.toUri() + JAR_URL_SEPARATOR + parts[2]);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract driver's nested .jar from " + jarUri + "; full uri: " + uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String platformDir() {
|
||||
String name = System.getProperty("os.name").toLowerCase();
|
||||
String arch = System.getProperty("os.arch").toLowerCase();
|
||||
|
||||
if (name.contains("windows")) {
|
||||
return "win32_x64";
|
||||
}
|
||||
if (name.contains("linux")) {
|
||||
if (arch.equals("aarch64")) {
|
||||
return "linux-arm64";
|
||||
} else {
|
||||
return "linux";
|
||||
}
|
||||
}
|
||||
if (name.contains("mac os x")) {
|
||||
if (arch.equals("aarch64")) {
|
||||
return "mac-arm64";
|
||||
} else {
|
||||
return "mac";
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unexpected os.name value: " + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path driverDir() {
|
||||
return driverTempDir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.Driver;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestInstall {
|
||||
@Test
|
||||
void playwrightCliInstalled() throws Exception {
|
||||
// Clear system property to ensure that the driver is loaded from jar.
|
||||
System.clearProperty("playwright.cli.dir");
|
||||
try {
|
||||
Path cli = Driver.ensureDriverInstalled();
|
||||
assertTrue(Files.exists(cli));
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(cli.toString(), "install");
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
Process p = pb.start();
|
||||
boolean result = p.waitFor(1, TimeUnit.MINUTES);
|
||||
assertTrue(result, "Timed out waiting for browsers to install");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
assertNull(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl.driver.jar;
|
||||
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.microsoft.playwright.impl.driver.Driver.PLAYWRIGHT_NODEJS_PATH;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestInstall {
|
||||
private static boolean isPortAvailable(int port) {
|
||||
try (ServerSocket ignored = new ServerSocket(port)) {
|
||||
return true;
|
||||
} catch (IOException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int unusedPort() {
|
||||
for (int i = 10000; i < 11000; i++) {
|
||||
if (isPortAvailable(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Cannot find unused local port");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void clearSystemProperties() {
|
||||
// Clear system property to ensure that the driver is loaded from jar.
|
||||
System.clearProperty("playwright.cli.dir");
|
||||
System.clearProperty("playwright.driver.tmpdir");
|
||||
System.clearProperty("playwright.nodejs.path");
|
||||
// Clear system property to ensure that the default driver is loaded.
|
||||
System.clearProperty("playwright.driver.impl");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowWhenBrowserPathIsInvalid(@TempDir Path tmpDir) throws NoSuchFieldException, IllegalAccessException {
|
||||
Map<String,String> env = new HashMap<>();
|
||||
|
||||
// On macOS we can only use 127.0.0.1, so pick unused port instead.
|
||||
// https://superuser.com/questions/458875/how-do-you-get-loopback-addresses-other-than-127-0-0-1-to-work-on-os-x
|
||||
env.put("PLAYWRIGHT_DOWNLOAD_HOST", "https://127.0.0.1:" + unusedPort());
|
||||
// Make sure the browsers are not installed yet by pointing at an empty dir.
|
||||
env.put("PLAYWRIGHT_BROWSERS_PATH", tmpDir.toString());
|
||||
env.put("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "false");
|
||||
|
||||
RuntimeException exception = assertThrows(RuntimeException.class, () -> Driver.createAndInstall(env, true));
|
||||
String message = exception.getMessage();
|
||||
assertTrue(message.contains("Failed to create driver"), message);
|
||||
}
|
||||
|
||||
@Test
|
||||
void playwrightCliInstalled() throws Exception {
|
||||
Driver driver = Driver.createAndInstall(Collections.emptyMap(), false);
|
||||
assertTrue(Files.exists(driver.driverDir()));
|
||||
|
||||
ProcessBuilder pb = driver.createProcessBuilder();
|
||||
pb.command().add("install");
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
Process p = pb.start();
|
||||
boolean result = p.waitFor(1, TimeUnit.MINUTES);
|
||||
assertTrue(result, "Timed out waiting for browsers to install");
|
||||
}
|
||||
|
||||
@Test
|
||||
void playwrightDriverInAlternativeTmpdir(@TempDir Path tmpdir) throws Exception {
|
||||
System.setProperty("playwright.driver.tmpdir", tmpdir.toString());
|
||||
DriverJar driver = new DriverJar();
|
||||
assertTrue(driver.driverDir().startsWith(tmpdir), "Driver path: " + driver.driverDir() + " tmp: " + tmpdir);
|
||||
}
|
||||
|
||||
@Test
|
||||
void playwrightDriverDefaultImpl() {
|
||||
assertDoesNotThrow(() -> Driver.createAndInstall(Collections.emptyMap(), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void playwrightDriverAlternativeImpl() throws NoSuchFieldException, IllegalAccessException {
|
||||
System.setProperty("playwright.driver.impl", "com.microsoft.playwright.impl.AlternativeDriver");
|
||||
RuntimeException thrown =
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
() -> Driver.createAndInstall(Collections.emptyMap(), false));
|
||||
assertEquals("Failed to create driver", thrown.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void canPassPreinstalledNodeJsAsSystemProperty(@TempDir Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
|
||||
String nodePath = extractNodeJsToTemp();
|
||||
System.setProperty("playwright.nodejs.path", nodePath);
|
||||
Driver driver = Driver.createAndInstall(Collections.emptyMap(), false);
|
||||
canSpecifyPreinstalledNodeJsShared(driver, tmpDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
void canSpecifyPreinstalledNodeJsAsEnv(@TempDir Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
|
||||
String nodePath = extractNodeJsToTemp();
|
||||
Driver driver = Driver.createAndInstall(singletonMap(PLAYWRIGHT_NODEJS_PATH, nodePath), false);
|
||||
canSpecifyPreinstalledNodeJsShared(driver, tmpDir);
|
||||
}
|
||||
|
||||
|
||||
private static String extractNodeJsToTemp() throws URISyntaxException, IOException {
|
||||
DriverJar auxDriver = new DriverJar();
|
||||
auxDriver.extractDriverToTempDir();
|
||||
String nodePath = auxDriver.driverDir().resolve(isWindows() ? "node.exe" : "node").toString();
|
||||
return nodePath;
|
||||
}
|
||||
|
||||
private static boolean isWindows() {
|
||||
String name = System.getProperty("os.name").toLowerCase();
|
||||
return name.contains("win");
|
||||
}
|
||||
|
||||
private static void canSpecifyPreinstalledNodeJsShared(Driver driver, Path tmpDir) throws IOException, URISyntaxException, InterruptedException {
|
||||
Path builtinNode = driver.driverDir().resolve("node");
|
||||
assertFalse(Files.exists(builtinNode), builtinNode.toString());
|
||||
Path builtinNodeExe = driver.driverDir().resolve("node.exe");
|
||||
assertFalse(Files.exists(builtinNodeExe), builtinNodeExe.toString());
|
||||
|
||||
ProcessBuilder pb = driver.createProcessBuilder();
|
||||
pb.command().add("--version");
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
Path out = tmpDir.resolve("out.txt");
|
||||
pb.redirectOutput(out.toFile());
|
||||
Process p = pb.start();
|
||||
boolean result = p.waitFor(1, TimeUnit.MINUTES);
|
||||
assertTrue(result, "Timed out waiting for version to be printed");
|
||||
String stdout = new String(Files.readAllBytes(out), StandardCharsets.UTF_8);
|
||||
assertTrue(stdout.contains("Version "), stdout);
|
||||
}
|
||||
}
|
||||
+30
-2
@@ -6,15 +6,43 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.50.0-SNAPSHOT</version>
|
||||
<version>0.180.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
<name>Playwright - Driver</name>
|
||||
<description>
|
||||
This module provides API for discovery and launching of Playwright driver.
|
||||
This module provides API for discovery and launching of playwright-cli binary.
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* This class provides access to playwright-cli. It can be either preinstalled
|
||||
* in the host system and its path is passed as a system property or it can be
|
||||
* loaded from the driver-bundle module if that module is in the classpath.
|
||||
*/
|
||||
public abstract class Driver {
|
||||
private static Driver instance;
|
||||
|
||||
private static class PreinstalledDriver extends Driver {
|
||||
private final Path driverDir;
|
||||
PreinstalledDriver(Path driverDir) {
|
||||
this.driverDir = driverDir;
|
||||
}
|
||||
@Override
|
||||
Path driverDir() {
|
||||
return driverDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized Path ensureDriverInstalled() {
|
||||
if (instance == null) {
|
||||
try {
|
||||
instance = createDriver();
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("Failed to create driver", exception);
|
||||
}
|
||||
}
|
||||
String name = instance.cliFileName();
|
||||
return instance.driverDir().resolve(name);
|
||||
}
|
||||
|
||||
protected String cliFileName() {
|
||||
return System.getProperty("os.name").toLowerCase().contains("windows") ?
|
||||
"playwright.cmd" : "playwright.sh";
|
||||
}
|
||||
|
||||
private static Driver createDriver() throws Exception {
|
||||
String pathFromProperty = System.getProperty("playwright.cli.dir");
|
||||
if (pathFromProperty != null) {
|
||||
return new PreinstalledDriver(Paths.get(pathFromProperty));
|
||||
}
|
||||
|
||||
Class<?> jarDriver = Class.forName("com.microsoft.playwright.impl.DriverJar");
|
||||
return (Driver) jarDriver.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
abstract Path driverDir();
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl.driver;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.driver.DriverLogging.logWithTimestamp;
|
||||
|
||||
/**
|
||||
* This class provides access to playwright-cli. It can be either preinstalled
|
||||
* in the host system and its path is passed as a system property or it can be
|
||||
* loaded from the driver-bundle module if that module is in the classpath.
|
||||
*/
|
||||
public abstract class Driver {
|
||||
protected final Map<String, String> env = new LinkedHashMap<>(System.getenv());
|
||||
public static final String PLAYWRIGHT_NODEJS_PATH = "PLAYWRIGHT_NODEJS_PATH";
|
||||
|
||||
private static Driver instance;
|
||||
|
||||
private static class PreinstalledDriver extends Driver {
|
||||
private final Path driverDir;
|
||||
PreinstalledDriver(Path driverDir) {
|
||||
logMessage("created PreinstalledDriver: " + driverDir);
|
||||
this.driverDir = driverDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(Boolean installBrowsers) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path driverDir() {
|
||||
return driverDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized Driver ensureDriverInstalled(Map<String, String> env, Boolean installBrowsers) {
|
||||
if (instance == null) {
|
||||
instance = createAndInstall(env, installBrowsers);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void initialize(Map<String, String> env, Boolean installBrowsers) throws Exception {
|
||||
this.env.putAll(env);
|
||||
initialize(installBrowsers);
|
||||
}
|
||||
protected abstract void initialize(Boolean installBrowsers) throws Exception;
|
||||
|
||||
public ProcessBuilder createProcessBuilder() {
|
||||
String nodePath = env.get("PLAYWRIGHT_NODEJS_PATH");
|
||||
if (nodePath == null) {
|
||||
String node = System.getProperty("os.name").toLowerCase().contains("windows") ? "node.exe" : "node";
|
||||
nodePath = driverDir().resolve(node).toAbsolutePath().toString();
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder(nodePath);
|
||||
pb.command().add(driverDir().resolve("package").resolve("cli.js").toAbsolutePath().toString());
|
||||
pb.environment().putAll(env);
|
||||
pb.environment().put("PW_LANG_NAME", "java");
|
||||
pb.environment().put("PW_LANG_NAME_VERSION", getMajorJavaVersion());
|
||||
String version = Driver.class.getPackage().getImplementationVersion();
|
||||
if (version != null) {
|
||||
pb.environment().put("PW_CLI_DISPLAY_VERSION", version);
|
||||
}
|
||||
return pb;
|
||||
}
|
||||
|
||||
private static String getMajorJavaVersion() {
|
||||
String version = System.getProperty("java.version");
|
||||
if (version.startsWith("1.")) {
|
||||
return version.substring(2, 3);
|
||||
}
|
||||
int dot = version.indexOf(".");
|
||||
if (dot != -1) {
|
||||
return version.substring(0, dot);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
public static Driver createAndInstall(Map<String, String> env, Boolean installBrowsers) {
|
||||
try {
|
||||
Driver instance = newInstance();
|
||||
logMessage("initializing driver");
|
||||
instance.initialize(env, installBrowsers);
|
||||
logMessage("driver initialized.");
|
||||
return instance;
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("Failed to create driver", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static Driver newInstance() throws Exception {
|
||||
String pathFromProperty = System.getProperty("playwright.cli.dir");
|
||||
if (pathFromProperty != null) {
|
||||
return new PreinstalledDriver(Paths.get(pathFromProperty));
|
||||
}
|
||||
|
||||
String driverImpl =
|
||||
System.getProperty("playwright.driver.impl", "com.microsoft.playwright.impl.driver.jar.DriverJar");
|
||||
Class<?> jarDriver = Class.forName(driverImpl);
|
||||
return (Driver) jarDriver.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
public abstract Path driverDir();
|
||||
|
||||
protected static void logMessage(String message) {
|
||||
// This matches log format produced by the server.
|
||||
logWithTimestamp("pw:install " + message);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl.driver;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
class DriverLogging {
|
||||
private static final boolean isEnabled;
|
||||
static {
|
||||
String debug = System.getenv("DEBUG");
|
||||
isEnabled = (debug != null) && debug.contains("pw:install");
|
||||
}
|
||||
|
||||
private static final DateTimeFormatter timestampFormat = DateTimeFormatter.ofPattern(
|
||||
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneId.of("UTC"));
|
||||
|
||||
static void logWithTimestamp(String message) {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
// This matches log format produced by the server.
|
||||
String timestamp = ZonedDateTime.now().format(timestampFormat);
|
||||
System.err.println(timestamp + " " + message);
|
||||
}
|
||||
}
|
||||
+3
-12
@@ -6,17 +6,16 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.50.0-SNAPSHOT</version>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<playwright.version>1.60.0</playwright.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>${playwright.version}</version>
|
||||
<version>0.180.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
@@ -24,7 +23,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -32,12 +31,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>snapshots-repo</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<releases><enabled>false</enabled></releases>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
|
||||
@@ -19,20 +19,22 @@ package org.example;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class EvaluateInBrowserContext {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.firefox().launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.example.com/");
|
||||
Object dimensions = page.evaluate("() => {\n" +
|
||||
" return {\n" +
|
||||
" width: document.documentElement.clientWidth,\n" +
|
||||
" height: document.documentElement.clientHeight,\n" +
|
||||
" deviceScaleFactor: window.devicePixelRatio\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
System.out.println(dimensions);
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.firefox();
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.example.com/");
|
||||
Object dimensions = page.evaluate("() => {\n" +
|
||||
" return {\n" +
|
||||
" width: document.documentElement.clientWidth,\n" +
|
||||
" height: document.documentElement.clientHeight,\n" +
|
||||
" deviceScaleFactor: window.devicePixelRatio\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
System.out.println(dimensions);
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,18 @@ package org.example;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class InterceptNetworkRequests {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.webkit().launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.route("**", route -> {
|
||||
System.out.println(route.request().url());
|
||||
route.resume();
|
||||
});
|
||||
page.navigate("http://todomvc.com");
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.webkit();
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.route("**", route -> {
|
||||
System.out.println(route.request().url());
|
||||
route.continue_();
|
||||
});
|
||||
page.navigate("http://todomvc.com");
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.example;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
@@ -24,22 +23,21 @@ import java.nio.file.Paths;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class MobileAndGeolocation {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.chromium().launch();
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36")
|
||||
.setViewportSize(411, 731)
|
||||
.setDeviceScaleFactor(2.625)
|
||||
.setIsMobile(true)
|
||||
.setHasTouch(true)
|
||||
.setLocale("en-US")
|
||||
.setGeolocation(41.889938, 12.492507)
|
||||
.setPermissions(asList("geolocation")));
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.openstreetmap.org/");
|
||||
page.click("a[data-original-title=\"Show My Location\"]");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("colosseum-pixel2.png")));
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
BrowserType browserType = playwright.chromium();
|
||||
Browser browser = browserType.launch(new BrowserType.LaunchOptions().withHeadless(false));
|
||||
DeviceDescriptor pixel2 = playwright.devices().get("Pixel 2");
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.withDevice(pixel2)
|
||||
.withLocale("en-US")
|
||||
.withGeolocation(new Geolocation(41.889938, 12.492507))
|
||||
.withPermissions(asList("geolocation")));
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://www.openstreetmap.org/");
|
||||
page.click("a[data-original-title=\"Show My Location\"]");
|
||||
page.screenshot(new Page.ScreenshotOptions().withPath(Paths.get("colosseum-pixel2.png")));
|
||||
browser.close();
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,21 +23,22 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PageScreenshot {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
List<BrowserType> browserTypes = Arrays.asList(
|
||||
playwright.chromium(),
|
||||
playwright.webkit(),
|
||||
playwright.firefox()
|
||||
);
|
||||
for (BrowserType browserType : browserTypes) {
|
||||
try (Browser browser = browserType.launch()) {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
Playwright playwright = Playwright.create();
|
||||
List<BrowserType> browserTypes = Arrays.asList(
|
||||
playwright.chromium(),
|
||||
playwright.webkit(),
|
||||
playwright.firefox()
|
||||
);
|
||||
for (BrowserType browserType : browserTypes) {
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions().withViewport(800, 600));
|
||||
Page page = context.newPage();
|
||||
page.navigate("http://whatsmyuseragent.org/");
|
||||
page.screenshot(new Page.ScreenshotOptions().withPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
browser.close();
|
||||
}
|
||||
playwright.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.example;
|
||||
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class PrintTitle {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.chromium().launch();
|
||||
Page page = browser.newPage();
|
||||
page.navigate("http://playwright.dev");
|
||||
System.out.println(page.title());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.example;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
public class SelectorsAndKeyboardManipulation {
|
||||
public static void main(String[] args) {
|
||||
try(Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.firefox().launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://playwright.dev/java/");
|
||||
page.locator("text=SearchK").click();
|
||||
page.locator("[placeholder=\"Search docs\"]").fill("getting started");
|
||||
page.locator("div[role=\"button\"]:has-text(\"CancelIntroductionGetting startedInstallationGetting startedUsageGetting start\")").click();
|
||||
page.waitForSelector("h1:has-text(\"Getting started\")"); // Waits for the new page to load before screenshotting.
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("Screenshot.png")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.example;
|
||||
|
||||
import com.microsoft.playwright.*;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class WebKitScreenshot {
|
||||
public static void main(String[] args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.webkit().launch();
|
||||
Page page = browser.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("example.png")));
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-35
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.50.0-SNAPSHOT</version>
|
||||
<version>0.180.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
@@ -23,61 +23,48 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration combine.self="append">
|
||||
<subpackages>com.microsoft.playwright</subpackages>
|
||||
<excludePackageNames>com.microsoft.playwright.impl</excludePackageNames>
|
||||
</configuration>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<subpackages>com.microsoft.playwright</subpackages>
|
||||
<excludePackageNames>com.microsoft.playwright.impl</excludePackageNames>
|
||||
<additionalOptions>--allow-script-in-comments</additionalOptions>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<targetPath>resources</targetPath>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
</dependency>
|
||||
<!--
|
||||
The following slf4j-simple dependency resolves the warning:
|
||||
'SLF4J(W): No SLF4J providers were found.'
|
||||
This warning is produced by the org.java-websocket library.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opentest4j</groupId>
|
||||
<artifactId>opentest4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>driver</artifactId>
|
||||
@@ -86,5 +73,10 @@
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Exposes API that can be used for the Web API testing. This class is used for creating {@code APIRequestContext} instance
|
||||
* which in turn can be used for sending web requests. An instance of this class can be obtained via {@link
|
||||
* com.microsoft.playwright.Playwright#request Playwright.request()}. For more information see {@code APIRequestContext}.
|
||||
*/
|
||||
public interface APIRequest {
|
||||
class NewContextOptions {
|
||||
/**
|
||||
* Methods like {@link com.microsoft.playwright.APIRequestContext#get APIRequestContext.get()} take the base URL into
|
||||
* consideration by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a>
|
||||
* constructor for building the corresponding URL. Examples:
|
||||
* <ul>
|
||||
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code
|
||||
* http://localhost:3000/bar.html}</li>
|
||||
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in {@code
|
||||
* http://localhost:3000/foo/bar.html}</li>
|
||||
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
|
||||
* {@code http://localhost:3000/bar.html}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public String baseURL;
|
||||
/**
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> Client certificate authentication is only active when at least one client certificate is provided. If you want to reject
|
||||
* all client certificates sent by the server, you need to provide a client certificate with an {@code origin} that does
|
||||
* not match any of the domains you plan to visit.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public List<ClientCertificate> clientCertificates;
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
*/
|
||||
public Map<String, String> extraHTTPHeaders;
|
||||
/**
|
||||
* Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes.
|
||||
*/
|
||||
public Boolean failOnStatusCode;
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
*/
|
||||
public HttpCredentials httpCredentials;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public Proxy proxy;
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link com.microsoft.playwright.BrowserContext#storageState BrowserContext.storageState()} or {@link
|
||||
* com.microsoft.playwright.APIRequestContext#storageState APIRequestContext.storageState()}. Either a path to the file
|
||||
* with saved storage, or the value returned by one of {@link com.microsoft.playwright.BrowserContext#storageState
|
||||
* BrowserContext.storageState()} or {@link com.microsoft.playwright.APIRequestContext#storageState
|
||||
* APIRequestContext.storageState()} methods.
|
||||
*/
|
||||
public String storageState;
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link com.microsoft.playwright.BrowserContext#storageState BrowserContext.storageState()}. Path to the
|
||||
* file with saved storage state.
|
||||
*/
|
||||
public Path storageStatePath;
|
||||
/**
|
||||
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable
|
||||
* timeout.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* Specific user agent to use in this context.
|
||||
*/
|
||||
public String userAgent;
|
||||
|
||||
/**
|
||||
* Methods like {@link com.microsoft.playwright.APIRequestContext#get APIRequestContext.get()} take the base URL into
|
||||
* consideration by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a>
|
||||
* constructor for building the corresponding URL. Examples:
|
||||
* <ul>
|
||||
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code
|
||||
* http://localhost:3000/bar.html}</li>
|
||||
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in {@code
|
||||
* http://localhost:3000/foo/bar.html}</li>
|
||||
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
|
||||
* {@code http://localhost:3000/bar.html}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public NewContextOptions setBaseURL(String baseURL) {
|
||||
this.baseURL = baseURL;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* TLS Client Authentication allows the server to request a client certificate and verify it.
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> An array of client certificates to be used. Each certificate object must have either both {@code certPath} and {@code
|
||||
* keyPath}, a single {@code pfxPath}, or their corresponding direct value equivalents ({@code cert} and {@code key}, or
|
||||
* {@code pfx}). Optionally, {@code passphrase} property should be provided if the certificate is encrypted. The {@code
|
||||
* origin} property should be provided with an exact match to the request origin that the certificate is valid for.
|
||||
*
|
||||
* <p> Client certificate authentication is only active when at least one client certificate is provided. If you want to reject
|
||||
* all client certificates sent by the server, you need to provide a client certificate with an {@code origin} that does
|
||||
* not match any of the domains you plan to visit.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When using WebKit on macOS, accessing {@code localhost} will not pick up client certificates. You can make it work by
|
||||
* replacing {@code localhost} with {@code local.playwright}.
|
||||
*/
|
||||
public NewContextOptions setClientCertificates(List<ClientCertificate> clientCertificates) {
|
||||
this.clientCertificates = clientCertificates;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
*/
|
||||
public NewContextOptions setExtraHTTPHeaders(Map<String, String> extraHTTPHeaders) {
|
||||
this.extraHTTPHeaders = extraHTTPHeaders;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes.
|
||||
*/
|
||||
public NewContextOptions setFailOnStatusCode(boolean failOnStatusCode) {
|
||||
this.failOnStatusCode = failOnStatusCode;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
*/
|
||||
public NewContextOptions setHttpCredentials(String username, String password) {
|
||||
return setHttpCredentials(new HttpCredentials(username, password));
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
*/
|
||||
public NewContextOptions setHttpCredentials(HttpCredentials httpCredentials) {
|
||||
this.httpCredentials = httpCredentials;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to ignore HTTPS errors when sending network requests. Defaults to {@code false}.
|
||||
*/
|
||||
public NewContextOptions setIgnoreHTTPSErrors(boolean ignoreHTTPSErrors) {
|
||||
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.
|
||||
*/
|
||||
public NewContextOptions setProxy(String server) {
|
||||
return setProxy(new Proxy(server));
|
||||
}
|
||||
/**
|
||||
* Network proxy settings.
|
||||
*/
|
||||
public NewContextOptions setProxy(Proxy proxy) {
|
||||
this.proxy = proxy;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link com.microsoft.playwright.BrowserContext#storageState BrowserContext.storageState()} or {@link
|
||||
* com.microsoft.playwright.APIRequestContext#storageState APIRequestContext.storageState()}. Either a path to the file
|
||||
* with saved storage, or the value returned by one of {@link com.microsoft.playwright.BrowserContext#storageState
|
||||
* BrowserContext.storageState()} or {@link com.microsoft.playwright.APIRequestContext#storageState
|
||||
* APIRequestContext.storageState()} methods.
|
||||
*/
|
||||
public NewContextOptions setStorageState(String storageState) {
|
||||
this.storageState = storageState;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link com.microsoft.playwright.BrowserContext#storageState BrowserContext.storageState()}. Path to the
|
||||
* file with saved storage state.
|
||||
*/
|
||||
public NewContextOptions setStorageStatePath(Path storageStatePath) {
|
||||
this.storageStatePath = storageStatePath;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable
|
||||
* timeout.
|
||||
*/
|
||||
public NewContextOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specific user agent to use in this context.
|
||||
*/
|
||||
public NewContextOptions setUserAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates new instances of {@code APIRequestContext}.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIRequestContext newContext() {
|
||||
return newContext(null);
|
||||
}
|
||||
/**
|
||||
* Creates new instances of {@code APIRequestContext}.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
APIRequestContext newContext(NewContextOptions options);
|
||||
}
|
||||
|
||||
@@ -1,493 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* This API is used for the Web API testing. You can use it to trigger API endpoints, configure micro-services, prepare
|
||||
* environment or the service to your e2e test.
|
||||
*
|
||||
* <p> Each Playwright browser context has an associated {@code APIRequestContext}, accessible via {@link
|
||||
* com.microsoft.playwright.BrowserContext#request BrowserContext.request()} or {@link
|
||||
* com.microsoft.playwright.Page#request Page.request()} (these return the
|
||||
*
|
||||
* <p> **same instance** — {@code page.request} is a shortcut for {@code page.context().request}). You can also create a
|
||||
* standalone, isolated instance with {@link com.microsoft.playwright.APIRequest#newContext APIRequest.newContext()}.
|
||||
*
|
||||
* <p> <strong>Cookie management</strong>
|
||||
*
|
||||
* <p> The {@code APIRequestContext} returned by {@link com.microsoft.playwright.BrowserContext#request
|
||||
* BrowserContext.request()} and
|
||||
*
|
||||
* <p> {@link com.microsoft.playwright.Page#request Page.request()} uses the same cookie jar as its {@code BrowserContext}:
|
||||
*
|
||||
* <p> If you want API requests that do **not** share cookies with the browser, create an isolated context via {@link
|
||||
* com.microsoft.playwright.APIRequest#newContext APIRequest.newContext()}. Such {@code APIRequestContext} object will have
|
||||
* its own isolated cookie storage.
|
||||
*/
|
||||
public interface APIRequestContext {
|
||||
class DisposeOptions {
|
||||
/**
|
||||
* The reason to be reported to the operations interrupted by the context disposal.
|
||||
*/
|
||||
public String reason;
|
||||
|
||||
/**
|
||||
* The reason to be reported to the operations interrupted by the context disposal.
|
||||
*/
|
||||
public DisposeOptions setReason(String reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StorageStateOptions {
|
||||
/**
|
||||
* Set to {@code true} to include IndexedDB in the storage state snapshot.
|
||||
*/
|
||||
public Boolean indexedDB;
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
*/
|
||||
public Path path;
|
||||
|
||||
/**
|
||||
* Set to {@code true} to include IndexedDB in the storage state snapshot.
|
||||
*/
|
||||
public StorageStateOptions setIndexedDB(boolean indexedDB) {
|
||||
this.indexedDB = indexedDB;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* The file path to save the storage state to. If {@code path} is a relative path, then it is resolved relative to current
|
||||
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||
*/
|
||||
public StorageStateOptions setPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE">DELETE</a> request and returns
|
||||
* its response. The method will populate request cookies from the context and update context cookies from the response.
|
||||
* The method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse delete(String url) {
|
||||
return delete(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE">DELETE</a> request and returns
|
||||
* its response. The method will populate request cookies from the context and update context cookies from the response.
|
||||
* The method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse delete(String url, RequestOptions params);
|
||||
/**
|
||||
* All responses returned by {@link com.microsoft.playwright.APIRequestContext#get APIRequestContext.get()} and similar
|
||||
* methods are stored in the memory, so that you can later call {@link com.microsoft.playwright.APIResponse#body
|
||||
* APIResponse.body()}.This method discards all its resources, calling any method on disposed {@code APIRequestContext}
|
||||
* will throw an exception.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
default void dispose() {
|
||||
dispose(null);
|
||||
}
|
||||
/**
|
||||
* All responses returned by {@link com.microsoft.playwright.APIRequestContext#get APIRequestContext.get()} and similar
|
||||
* methods are stored in the memory, so that you can later call {@link com.microsoft.playwright.APIResponse#body
|
||||
* APIResponse.body()}.This method discards all its resources, calling any method on disposed {@code APIRequestContext}
|
||||
* will throw an exception.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
void dispose(DisposeOptions options);
|
||||
/**
|
||||
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse fetch(String urlOrRequest) {
|
||||
return fetch(urlOrRequest, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse fetch(String urlOrRequest, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse fetch(Request urlOrRequest) {
|
||||
return fetch(urlOrRequest, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding, by specifiying the {@code multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse fetch(Request urlOrRequest, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET">GET</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Request parameters can be configured with {@code params} option, they will be serialized into the URL search parameters:
|
||||
* <pre>{@code
|
||||
* request.get("https://example.com/api/getText", RequestOptions.create()
|
||||
* .setQueryParam("isbn", "1234")
|
||||
* .setQueryParam("page", 23));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse get(String url) {
|
||||
return get(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET">GET</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Request parameters can be configured with {@code params} option, they will be serialized into the URL search parameters:
|
||||
* <pre>{@code
|
||||
* request.get("https://example.com/api/getText", RequestOptions.create()
|
||||
* .setQueryParam("isbn", "1234")
|
||||
* .setQueryParam("page", 23));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse get(String url, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD">HEAD</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse head(String url) {
|
||||
return head(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD">HEAD</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse head(String url, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH">PATCH</a> request and returns
|
||||
* its response. The method will populate request cookies from the context and update context cookies from the response.
|
||||
* The method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse patch(String url) {
|
||||
return patch(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH">PATCH</a> request and returns
|
||||
* its response. The method will populate request cookies from the context and update context cookies from the response.
|
||||
* The method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse patch(String url, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with {@code
|
||||
* application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send
|
||||
* files):
|
||||
* <pre>{@code
|
||||
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
|
||||
* FormData.create().set("title", "Book Title").set("body", "John Doe")
|
||||
* ));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload1 = new FilePayload("f1.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.post("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse post(String url) {
|
||||
return post(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with {@code
|
||||
* application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send
|
||||
* files):
|
||||
* <pre>{@code
|
||||
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
|
||||
* FormData.create().set("title", "Book Title").set("body", "John Doe")
|
||||
* ));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. Use {@code FormData} to construct request body and pass it to the request as {@code
|
||||
* multipart} parameter:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload1 = new FilePayload("f1.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.post("https://example.com/api/uploadScript",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse post(String url, RequestOptions params);
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">PUT</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse put(String url) {
|
||||
return put(url, null);
|
||||
}
|
||||
/**
|
||||
* Sends HTTP(S) <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">PUT</a> request and returns its
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse put(String url, RequestOptions params);
|
||||
/**
|
||||
* Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to
|
||||
* the constructor.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
default String storageState() {
|
||||
return storageState(null);
|
||||
}
|
||||
/**
|
||||
* Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to
|
||||
* the constructor.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
String storageState(StorageStateOptions options);
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
Tracing tracing();
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code APIResponse} class represents responses returned by {@link com.microsoft.playwright.APIRequestContext#get
|
||||
* APIRequestContext.get()} and similar methods.
|
||||
*/
|
||||
public interface APIResponse {
|
||||
/**
|
||||
* Returns the buffer with response body.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
byte[] body();
|
||||
/**
|
||||
* Disposes the body of this response. If not called then the body will stay in memory until the context closes.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
void dispose();
|
||||
/**
|
||||
* An object with all the response HTTP headers associated with this response.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
Map<String, String> headers();
|
||||
/**
|
||||
* An array with all the response HTTP headers associated with this response. Header names are not lower-cased. Headers
|
||||
* with multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
List<HttpHeader> headersArray();
|
||||
/**
|
||||
* Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
boolean ok();
|
||||
/**
|
||||
* Contains the status code of the response (e.g., 200 for a success).
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
int status();
|
||||
/**
|
||||
* Contains the status text of the response (e.g. usually an "OK" for a success).
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
String statusText();
|
||||
/**
|
||||
* Returns the text representation of response body.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
String text();
|
||||
/**
|
||||
* Contains the URL of the response.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by
|
||||
* assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or
|
||||
* [switches](https://en.wikipedia.org/wiki/Switch_access).
|
||||
*
|
||||
* <p> Accessibility is a very platform-specific thing. On different platforms, there are different screen readers that might
|
||||
* have wildly different output.
|
||||
*
|
||||
* <p> Rendering engines of Chromium, Firefox and Webkit have a concept of "accessibility tree", which is then translated into
|
||||
* different platform-specific APIs. Accessibility namespace gives access to this Accessibility Tree.
|
||||
*
|
||||
* <p> Most of the accessibility tree gets filtered out when converting from internal browser AX Tree to Platform-specific
|
||||
* AX-Tree or by assistive technologies themselves. By default, Playwright tries to approximate this filtering, exposing
|
||||
* only the "interesting" nodes of the tree.
|
||||
*/
|
||||
public interface Accessibility {
|
||||
class SnapshotOptions {
|
||||
/**
|
||||
* Prune uninteresting nodes from the tree. Defaults to {@code true}.
|
||||
*/
|
||||
public Boolean interestingOnly;
|
||||
/**
|
||||
* The root DOM element for the snapshot. Defaults to the whole page.
|
||||
*/
|
||||
public ElementHandle root;
|
||||
|
||||
public SnapshotOptions withInterestingOnly(boolean interestingOnly) {
|
||||
this.interestingOnly = interestingOnly;
|
||||
return this;
|
||||
}
|
||||
public SnapshotOptions withRoot(ElementHandle root) {
|
||||
this.root = root;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
default AccessibilityNode snapshot() {
|
||||
return snapshot(null);
|
||||
}
|
||||
/**
|
||||
* Captures the current state of the accessibility tree. The returned object represents the root accessible node of the
|
||||
* page.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The Chromium accessibility tree contains nodes that go unused on most platforms and by most screen readers.
|
||||
* Playwright will discard them as well for an easier to process tree, unless {@code interestingOnly} is set to {@code false}.
|
||||
*/
|
||||
AccessibilityNode snapshot(SnapshotOptions options);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AccessibilityNode {
|
||||
String role();
|
||||
String name();
|
||||
String valueString();
|
||||
Double valueNumber();
|
||||
String description();
|
||||
String keyshortcuts();
|
||||
String roledescription();
|
||||
String valuetext();
|
||||
Boolean disabled();
|
||||
Boolean expanded();
|
||||
Boolean focused();
|
||||
Boolean modal();
|
||||
Boolean multiline();
|
||||
Boolean multiselectable();
|
||||
Boolean readonly();
|
||||
Boolean required();
|
||||
Boolean selected();
|
||||
enum CheckedState { CHECKED, UNCHECKED, MIXED }
|
||||
CheckedState checked();
|
||||
enum PressedState { PRESSED, RELEASED, MIXED }
|
||||
PressedState pressed();
|
||||
Integer level();
|
||||
Double valuemin();
|
||||
Double valuemax();
|
||||
String autocomplete();
|
||||
String haspopup();
|
||||
String invalid();
|
||||
String orientation();
|
||||
List<AccessibilityNode> children();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@code CDPSession} instances are used to talk raw Chrome Devtools Protocol:
|
||||
* <ul>
|
||||
* <li> protocol methods can be called with {@code session.send} method.</li>
|
||||
* <li> protocol events can be subscribed to with {@code session.on} method.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Useful links:
|
||||
* <ul>
|
||||
* <li> Documentation on DevTools Protocol can be found here: <a
|
||||
* href="https://chromedevtools.github.io/devtools-protocol/">DevTools Protocol Viewer</a>.</li>
|
||||
* <li> Getting Started with DevTools Protocol: https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md</li>
|
||||
* </ul>
|
||||
* <pre>{@code
|
||||
* CDPSession client = page.context().newCDPSession(page);
|
||||
* client.send("Runtime.enable");
|
||||
*
|
||||
* client.on("Animation.animationCreated", (event) -> System.out.println("Animation created!"));
|
||||
*
|
||||
* JsonObject response = client.send("Animation.getPlaybackRate");
|
||||
* double playbackRate = response.get("playbackRate").getAsDouble();
|
||||
* System.out.println("playback rate is " + playbackRate);
|
||||
*
|
||||
* JsonObject params = new JsonObject();
|
||||
* params.addProperty("playbackRate", playbackRate / 2);
|
||||
* client.send("Animation.setPlaybackRate", params);
|
||||
* }</pre>
|
||||
*/
|
||||
public interface CDPSession {
|
||||
|
||||
/**
|
||||
* Emitted when the session is closed, either because the target was closed or {@code session.detach()} was called.
|
||||
*/
|
||||
void onClose(Consumer<CDPSession> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onClose onClose(handler)}.
|
||||
*/
|
||||
void offClose(Consumer<CDPSession> handler);
|
||||
|
||||
/**
|
||||
* Detaches the CDPSession from the target. Once detached, the CDPSession object won't emit any events and can't be used to
|
||||
* send messages.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void detach();
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param method Protocol method name.
|
||||
* @since v1.8
|
||||
*/
|
||||
default JsonObject send(String method) {
|
||||
return send(method, null);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param method Protocol method name.
|
||||
* @param args Optional method parameters.
|
||||
* @since v1.8
|
||||
*/
|
||||
JsonObject send(String method, JsonObject args);
|
||||
/**
|
||||
* Register an event handler for events with the specified event name. The given handler will be called for every event
|
||||
* with the given name.
|
||||
*
|
||||
* @param eventName CDP event name.
|
||||
* @param handler Event handler.
|
||||
* @since v1.37
|
||||
*/
|
||||
void on(String eventName, Consumer<JsonObject> handler);
|
||||
/**
|
||||
* Unregister an event handler for events with the specified event name. The given handler will not be called anymore for
|
||||
* events with the given name.
|
||||
*
|
||||
* @param eventName CDP event name.
|
||||
* @param handler Event handler.
|
||||
* @since v1.37
|
||||
*/
|
||||
void off(String eventName, Consumer<JsonObject> handler);
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Use this class to launch playwright cli.
|
||||
*/
|
||||
public class CLI {
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
Driver driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
|
||||
ProcessBuilder pb = driver.createProcessBuilder();
|
||||
pb.command().addAll(asList(args));
|
||||
String version = Playwright.class.getPackage().getImplementationVersion();
|
||||
if (version != null) {
|
||||
pb.environment().put("PW_CLI_DISPLAY_VERSION", version);
|
||||
}
|
||||
pb.inheritIO();
|
||||
Process process = pb.start();
|
||||
System.exit(process.waitFor());
|
||||
}
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Accurately simulating time-dependent behavior is essential for verifying the correctness of applications. Learn more
|
||||
* about <a href="https://playwright.dev/java/docs/clock">clock emulation</a>.
|
||||
*
|
||||
* <p> Note that clock is installed for the entire {@code BrowserContext}, so the time in all the pages and iframes is
|
||||
* controlled by the same clock.
|
||||
*/
|
||||
public interface Clock {
|
||||
class InstallOptions {
|
||||
/**
|
||||
* Time to initialize with, current system time by default.
|
||||
*/
|
||||
public Object time;
|
||||
|
||||
/**
|
||||
* Time to initialize with, current system time by default.
|
||||
*/
|
||||
public InstallOptions setTime(long time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to initialize with, current system time by default.
|
||||
*/
|
||||
public InstallOptions setTime(String time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to initialize with, current system time by default.
|
||||
*/
|
||||
public InstallOptions setTime(Date time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Advance the clock by jumping forward in time. Only fires due timers at most once. This is equivalent to user closing the
|
||||
* laptop lid for a while and reopening it later, after given time.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().fastForward(1000);
|
||||
* page.clock().fastForward("30:00");
|
||||
* }</pre>
|
||||
*
|
||||
* @param ticks Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08"
|
||||
* for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void fastForward(long ticks);
|
||||
/**
|
||||
* Advance the clock by jumping forward in time. Only fires due timers at most once. This is equivalent to user closing the
|
||||
* laptop lid for a while and reopening it later, after given time.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().fastForward(1000);
|
||||
* page.clock().fastForward("30:00");
|
||||
* }</pre>
|
||||
*
|
||||
* @param ticks Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08"
|
||||
* for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void fastForward(String ticks);
|
||||
/**
|
||||
* Install fake implementations for the following time-related functions:
|
||||
* <ul>
|
||||
* <li> {@code Date}</li>
|
||||
* <li> {@code setTimeout}</li>
|
||||
* <li> {@code clearTimeout}</li>
|
||||
* <li> {@code setInterval}</li>
|
||||
* <li> {@code clearInterval}</li>
|
||||
* <li> {@code requestAnimationFrame}</li>
|
||||
* <li> {@code cancelAnimationFrame}</li>
|
||||
* <li> {@code requestIdleCallback}</li>
|
||||
* <li> {@code cancelIdleCallback}</li>
|
||||
* <li> {@code performance}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Fake timers are used to manually control the flow of time in tests. They allow you to advance time, fire timers, and
|
||||
* control the behavior of time-dependent functions. See {@link com.microsoft.playwright.Clock#runFor Clock.runFor()} and
|
||||
* {@link com.microsoft.playwright.Clock#fastForward Clock.fastForward()} for more information.
|
||||
*
|
||||
* @since v1.45
|
||||
*/
|
||||
default void install() {
|
||||
install(null);
|
||||
}
|
||||
/**
|
||||
* Install fake implementations for the following time-related functions:
|
||||
* <ul>
|
||||
* <li> {@code Date}</li>
|
||||
* <li> {@code setTimeout}</li>
|
||||
* <li> {@code clearTimeout}</li>
|
||||
* <li> {@code setInterval}</li>
|
||||
* <li> {@code clearInterval}</li>
|
||||
* <li> {@code requestAnimationFrame}</li>
|
||||
* <li> {@code cancelAnimationFrame}</li>
|
||||
* <li> {@code requestIdleCallback}</li>
|
||||
* <li> {@code cancelIdleCallback}</li>
|
||||
* <li> {@code performance}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Fake timers are used to manually control the flow of time in tests. They allow you to advance time, fire timers, and
|
||||
* control the behavior of time-dependent functions. See {@link com.microsoft.playwright.Clock#runFor Clock.runFor()} and
|
||||
* {@link com.microsoft.playwright.Clock#fastForward Clock.fastForward()} for more information.
|
||||
*
|
||||
* @since v1.45
|
||||
*/
|
||||
void install(InstallOptions options);
|
||||
/**
|
||||
* Advance the clock, firing all the time-related callbacks.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().runFor(1000);
|
||||
* page.clock().runFor("30:00");
|
||||
* }</pre>
|
||||
*
|
||||
* @param ticks Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08"
|
||||
* for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void runFor(long ticks);
|
||||
/**
|
||||
* Advance the clock, firing all the time-related callbacks.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().runFor(1000);
|
||||
* page.clock().runFor("30:00");
|
||||
* }</pre>
|
||||
*
|
||||
* @param ticks Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08"
|
||||
* for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void runFor(String ticks);
|
||||
/**
|
||||
* Advance the clock by jumping forward in time and pause the time. Once this method is called, no timers are fired unless
|
||||
* {@link com.microsoft.playwright.Clock#runFor Clock.runFor()}, {@link com.microsoft.playwright.Clock#fastForward
|
||||
* Clock.fastForward()}, {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} or {@link
|
||||
* com.microsoft.playwright.Clock#resume Clock.resume()} is called.
|
||||
*
|
||||
* <p> Only fires due timers at most once. This is equivalent to user closing the laptop lid for a while and reopening it at
|
||||
* the specified time and pausing.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd");
|
||||
* page.clock().pauseAt(format.parse("2020-02-02"));
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
void pauseAt(long time);
|
||||
/**
|
||||
* Advance the clock by jumping forward in time and pause the time. Once this method is called, no timers are fired unless
|
||||
* {@link com.microsoft.playwright.Clock#runFor Clock.runFor()}, {@link com.microsoft.playwright.Clock#fastForward
|
||||
* Clock.fastForward()}, {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} or {@link
|
||||
* com.microsoft.playwright.Clock#resume Clock.resume()} is called.
|
||||
*
|
||||
* <p> Only fires due timers at most once. This is equivalent to user closing the laptop lid for a while and reopening it at
|
||||
* the specified time and pausing.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd");
|
||||
* page.clock().pauseAt(format.parse("2020-02-02"));
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
void pauseAt(String time);
|
||||
/**
|
||||
* Advance the clock by jumping forward in time and pause the time. Once this method is called, no timers are fired unless
|
||||
* {@link com.microsoft.playwright.Clock#runFor Clock.runFor()}, {@link com.microsoft.playwright.Clock#fastForward
|
||||
* Clock.fastForward()}, {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} or {@link
|
||||
* com.microsoft.playwright.Clock#resume Clock.resume()} is called.
|
||||
*
|
||||
* <p> Only fires due timers at most once. This is equivalent to user closing the laptop lid for a while and reopening it at
|
||||
* the specified time and pausing.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd");
|
||||
* page.clock().pauseAt(format.parse("2020-02-02"));
|
||||
* page.clock().pauseAt("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> For best results, install the clock before navigating the page and set it to a time slightly before the intended test
|
||||
* time. This ensures that all timers run normally during page loading, preventing the page from getting stuck. Once the
|
||||
* page has fully loaded, you can safely use {@link com.microsoft.playwright.Clock#pauseAt Clock.pauseAt()} to pause the
|
||||
* clock.
|
||||
* <pre>{@code
|
||||
* // Initialize clock with some time before the test time and let the page load
|
||||
* // naturally. `Date.now` will progress as the timers fire.
|
||||
* SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
|
||||
* page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-12-10T08:00:00")));
|
||||
* page.navigate("http://localhost:3333");
|
||||
* page.clock().pauseAt(format.parse("2024-12-10T10:00:00"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to pause at.
|
||||
* @since v1.45
|
||||
*/
|
||||
void pauseAt(Date time);
|
||||
/**
|
||||
* Resumes timers. Once this method is called, time resumes flowing, timers are fired as usual.
|
||||
*
|
||||
* @since v1.45
|
||||
*/
|
||||
void resume();
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
* page.clock().setFixedTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setFixedTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setFixedTime(long time);
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
* page.clock().setFixedTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setFixedTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setFixedTime(String time);
|
||||
/**
|
||||
* Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
|
||||
*
|
||||
* <p> Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios,
|
||||
* use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on <a
|
||||
* href="https://playwright.dev/java/docs/clock">clock emulation</a> to learn more.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setFixedTime(new Date());
|
||||
* page.clock().setFixedTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setFixedTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setFixedTime(Date time);
|
||||
/**
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setSystemTime(new Date());
|
||||
* page.clock().setSystemTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setSystemTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setSystemTime(long time);
|
||||
/**
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setSystemTime(new Date());
|
||||
* page.clock().setSystemTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setSystemTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setSystemTime(String time);
|
||||
/**
|
||||
* Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
|
||||
* switching from summer to winter time, or changing time zones.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.clock().setSystemTime(new Date());
|
||||
* page.clock().setSystemTime(new SimpleDateFormat("yyy-MM-dd").parse("2020-02-02"));
|
||||
* page.clock().setSystemTime("2020-02-02");
|
||||
* }</pre>
|
||||
*
|
||||
* @param time Time to be set in milliseconds.
|
||||
* @since v1.45
|
||||
*/
|
||||
void setSystemTime(Date time);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
@@ -19,77 +19,41 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code ConsoleMessage} objects are dispatched by page via the {@link com.microsoft.playwright.Page#onConsoleMessage
|
||||
* Page.onConsoleMessage()} event. For each console message logged in the page there will be corresponding event in the
|
||||
* Playwright context.
|
||||
* <pre>{@code
|
||||
* // Listen for all console messages and print them to the standard output.
|
||||
* page.onConsoleMessage(msg -> System.out.println(msg.text()));
|
||||
*
|
||||
* // Listen for all console messages and print errors to the standard output.
|
||||
* page.onConsoleMessage(msg -> {
|
||||
* if ("error".equals(msg.type()))
|
||||
* System.out.println("Error text: " + msg.text());
|
||||
* });
|
||||
*
|
||||
* // Get the next console message
|
||||
* ConsoleMessage msg = page.waitForConsoleMessage(() -> {
|
||||
* // Issue console.log inside the page
|
||||
* page.evaluate("console.log('hello', 42, { foo: 'bar' });");
|
||||
* });
|
||||
*
|
||||
* // Deconstruct console.log arguments
|
||||
* msg.args().get(0).jsonValue(); // hello
|
||||
* msg.args().get(1).jsonValue(); // 42
|
||||
* }</pre>
|
||||
* {@code ConsoleMessage} objects are dispatched by page via the [{@code event: Page.console}] event.
|
||||
*/
|
||||
public interface ConsoleMessage {
|
||||
/**
|
||||
* List of arguments passed to a {@code console} function call. See also {@link
|
||||
* com.microsoft.playwright.Page#onConsoleMessage Page.onConsoleMessage()}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
class Location {
|
||||
/**
|
||||
* URL of the resource.
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 0-based line number in the resource.
|
||||
*/
|
||||
private int lineNumber;
|
||||
/**
|
||||
* 0-based column number in the resource.
|
||||
*/
|
||||
private int columnNumber;
|
||||
|
||||
public String url() {
|
||||
return this.url;
|
||||
}
|
||||
public int lineNumber() {
|
||||
return this.lineNumber;
|
||||
}
|
||||
public int columnNumber() {
|
||||
return this.columnNumber;
|
||||
}
|
||||
}
|
||||
List<JSHandle> args();
|
||||
/**
|
||||
* URL of the resource followed by 0-based line and column numbers in the resource formatted as {@code URL:line:column}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String location();
|
||||
/**
|
||||
* The page that produced this console message, if any.
|
||||
*
|
||||
* @since v1.34
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* The text of the console message.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Location location();
|
||||
String text();
|
||||
/**
|
||||
* The timestamp of the console message in milliseconds since the Unix epoch.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
double timestamp();
|
||||
/**
|
||||
* One of the following values: {@code "log"}, {@code "debug"}, {@code "info"}, {@code "error"}, {@code "warning"}, {@code
|
||||
* "dir"}, {@code "dirxml"}, {@code "table"}, {@code "trace"}, {@code "clear"}, {@code "startGroup"}, {@code
|
||||
* "startGroupCollapsed"}, {@code "endGroup"}, {@code "assert"}, {@code "profile"}, {@code "profileEnd"}, {@code "count"},
|
||||
* {@code "timeEnd"}.
|
||||
*
|
||||
* @since v1.8
|
||||
* One of the following values: {@code 'log'}, {@code 'debug'}, {@code 'info'}, {@code 'error'}, {@code 'warning'}, {@code 'dir'}, {@code 'dirxml'}, {@code 'table'},
|
||||
* {@code 'trace'}, {@code 'clear'}, {@code 'startGroup'}, {@code 'startGroupCollapsed'}, {@code 'endGroup'}, {@code 'assert'}, {@code 'profile'}, {@code 'profileEnd'},
|
||||
* {@code 'count'}, {@code 'timeEnd'}.
|
||||
*/
|
||||
String type();
|
||||
/**
|
||||
* The web worker or service worker that produced this console message, if any. Note that console messages from web workers
|
||||
* also have non-null {@link com.microsoft.playwright.ConsoleMessage#page ConsoleMessage.page()}.
|
||||
*
|
||||
* @since v1.57
|
||||
*/
|
||||
Worker worker();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* API for controlling the Playwright debugger. The debugger allows pausing script execution and inspecting the page.
|
||||
* Obtain the debugger instance via {@link com.microsoft.playwright.BrowserContext#debugger BrowserContext.debugger()}.
|
||||
*/
|
||||
public interface Debugger {
|
||||
|
||||
/**
|
||||
* Emitted when the debugger pauses or resumes.
|
||||
*/
|
||||
void onPausedStateChanged(Runnable handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onPausedStateChanged onPausedStateChanged(handler)}.
|
||||
*/
|
||||
void offPausedStateChanged(Runnable handler);
|
||||
|
||||
/**
|
||||
* Returns details about the currently paused call. Returns {@code null} if the debugger is not paused.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
DebuggerPausedDetails pausedDetails();
|
||||
/**
|
||||
* Configures the debugger to pause before the next action is executed.
|
||||
*
|
||||
* <p> Throws if the debugger is already paused. Use {@link com.microsoft.playwright.Debugger#next Debugger.next()} or {@link
|
||||
* com.microsoft.playwright.Debugger#runTo Debugger.runTo()} to step while paused.
|
||||
*
|
||||
* <p> Note that {@link com.microsoft.playwright.Page#pause Page.pause()} is equivalent to a "debugger" statement — it pauses
|
||||
* execution at the call site immediately. On the contrary, {@link com.microsoft.playwright.Debugger#requestPause
|
||||
* Debugger.requestPause()} is equivalent to "pause on next statement" — it configures the debugger to pause before the
|
||||
* next action is executed.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void requestPause();
|
||||
/**
|
||||
* Resumes script execution. Throws if the debugger is not paused.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void resume();
|
||||
/**
|
||||
* Resumes script execution and pauses again before the next action. Throws if the debugger is not paused.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void next();
|
||||
/**
|
||||
* Resumes script execution and pauses when an action originates from the given source location. Throws if the debugger is
|
||||
* not paused.
|
||||
*
|
||||
* @param location The source location to pause at.
|
||||
* @since v1.59
|
||||
*/
|
||||
void runTo(Location location);
|
||||
}
|
||||
|
||||
+15
-19
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -16,19 +16,15 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public interface ScreencastFrame {
|
||||
/**
|
||||
* JPEG-encoded frame data.
|
||||
*/
|
||||
byte[] data();
|
||||
|
||||
/**
|
||||
* Width of the page viewport at the time the frame was captured.
|
||||
*/
|
||||
int viewportWidth();
|
||||
|
||||
/**
|
||||
* Height of the page viewport at the time the frame was captured.
|
||||
*/
|
||||
int viewportHeight();
|
||||
}
|
||||
public interface DeviceDescriptor {
|
||||
interface Viewport {
|
||||
int width();
|
||||
int height();
|
||||
}
|
||||
Viewport viewport();
|
||||
String userAgent();
|
||||
double deviceScaleFactor();
|
||||
boolean isMobile();
|
||||
boolean hasTouch();
|
||||
BrowserType defaultBrowserType();
|
||||
}
|
||||
@@ -16,44 +16,14 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code Dialog} objects are dispatched by page via the {@link com.microsoft.playwright.Page#onDialog Page.onDialog()}
|
||||
* event.
|
||||
*
|
||||
* <p> An example of using {@code Dialog} class:
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.*;
|
||||
*
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType chromium = playwright.chromium();
|
||||
* Browser browser = chromium.launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.onDialog(dialog -> {
|
||||
* System.out.println(dialog.message());
|
||||
* dialog.dismiss();
|
||||
* });
|
||||
* page.evaluate("alert('1')");
|
||||
* browser.close();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Dialogs are dismissed automatically, unless there is a {@link com.microsoft.playwright.Page#onDialog Page.onDialog()}
|
||||
* listener. When listener is present, it **must** either {@link com.microsoft.playwright.Dialog#accept Dialog.accept()} or
|
||||
* {@link com.microsoft.playwright.Dialog#dismiss Dialog.dismiss()} the dialog - otherwise the page will <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking">freeze</a> waiting for the
|
||||
* dialog, and actions like click will never finish.
|
||||
* {@code Dialog} objects are dispatched by page via the [{@code event: Page.dialog}] event.
|
||||
*/
|
||||
public interface Dialog {
|
||||
/**
|
||||
* Returns when the dialog has been accepted.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
enum Type { ALERT, BEFOREUNLOAD, CONFIRM, PROMPT }
|
||||
|
||||
default void accept() {
|
||||
accept(null);
|
||||
}
|
||||
@@ -61,38 +31,23 @@ public interface Dialog {
|
||||
* Returns when the dialog has been accepted.
|
||||
*
|
||||
* @param promptText A text to enter in prompt. Does not cause any effects if the dialog's {@code type} is not prompt. Optional.
|
||||
* @since v1.8
|
||||
*/
|
||||
void accept(String promptText);
|
||||
/**
|
||||
* If dialog is prompt, returns default prompt value. Otherwise, returns empty string.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String defaultValue();
|
||||
/**
|
||||
* Returns when the dialog has been dismissed.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void dismiss();
|
||||
/**
|
||||
* A message displayed in the dialog.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String message();
|
||||
/**
|
||||
* The page that initiated this dialog, if available.
|
||||
*
|
||||
* @since v1.34
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Returns dialog's type, can be one of {@code alert}, {@code beforeunload}, {@code confirm} or {@code prompt}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String type();
|
||||
Type type();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,97 +18,52 @@ package com.microsoft.playwright;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code Download} objects are dispatched by page via the {@link com.microsoft.playwright.Page#onDownload
|
||||
* Page.onDownload()} event.
|
||||
* {@code Download} objects are dispatched by page via the [{@code event: Page.download}] event.
|
||||
*
|
||||
* <p> All the downloaded files belonging to the browser context are deleted when the browser context is closed.
|
||||
* <p> All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded
|
||||
* files are deleted when the browser closes.
|
||||
*
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes.
|
||||
* <pre>{@code
|
||||
* // Wait for the download to start
|
||||
* Download download = page.waitForDownload(() -> {
|
||||
* // Perform the action that initiates download
|
||||
* page.getByText("Download file").click();
|
||||
* });
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
|
||||
*
|
||||
* // Wait for the download process to complete and save the downloaded file somewhere
|
||||
* download.saveAs(Paths.get("/path/to/save/at/", download.suggestedFilename()));
|
||||
* }</pre>
|
||||
* <p> <strong>NOTE:</strong> Browser context **must** be created with the {@code acceptDownloads} set to {@code true} when user needs access to the
|
||||
* downloaded content. If {@code acceptDownloads} is not set, download events are emitted, but the actual download is not
|
||||
* performed and user has no access to the downloaded files.
|
||||
*/
|
||||
public interface Download {
|
||||
/**
|
||||
* Cancels a download. Will not fail if the download is already finished or canceled. Upon successful cancellations, {@code
|
||||
* download.failure()} would resolve to {@code "canceled"}.
|
||||
*
|
||||
* @since v1.13
|
||||
*/
|
||||
void cancel();
|
||||
/**
|
||||
* Returns a readable stream for a successful download, or throws for a failed/canceled download.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> If you don't need a readable stream, it's usually simpler to read the file from disk after the download completed. See
|
||||
* {@link com.microsoft.playwright.Download#path Download.path()}.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns readable stream for current download or {@code null} if download failed.
|
||||
*/
|
||||
InputStream createReadStream();
|
||||
/**
|
||||
* Deletes the downloaded file. Will wait for the download to finish if necessary.
|
||||
*
|
||||
* @since v1.8
|
||||
* Deletes the downloaded file.
|
||||
*/
|
||||
void delete();
|
||||
/**
|
||||
* Returns download error if any. Will wait for the download to finish if necessary.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns download error if any.
|
||||
*/
|
||||
String failure();
|
||||
/**
|
||||
* Get the page that the download belongs to.
|
||||
*
|
||||
* @since v1.12
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Returns path to the downloaded file for a successful download, or throws for a failed/canceled download. The method will
|
||||
* wait for the download to finish if necessary. The method throws when connected remotely.
|
||||
*
|
||||
* <p> Note that the download's file name is a random GUID, use {@link com.microsoft.playwright.Download#suggestedFilename
|
||||
* Download.suggestedFilename()} to get suggested file name.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns path to the downloaded file in case of successful download.
|
||||
*/
|
||||
Path path();
|
||||
/**
|
||||
* Copy the download to a user-specified path. It is safe to call this method while the download is still in progress. Will
|
||||
* wait for the download to finish if necessary.
|
||||
* Saves the download to a user-specified path.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* download.saveAs(Paths.get("/path/to/save/at/", download.suggestedFilename()));
|
||||
* }</pre>
|
||||
*
|
||||
* @param path Path where the download should be copied.
|
||||
* @since v1.8
|
||||
* @param path Path where the download should be saved.
|
||||
*/
|
||||
void saveAs(Path path);
|
||||
/**
|
||||
* Returns suggested filename for this download. It is typically computed by the browser from the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition">{@code Content-Disposition}</a>
|
||||
* response header or the {@code download} attribute. See the spec on <a
|
||||
* href="https://html.spec.whatwg.org/#downloading-resources">whatwg</a>. Different browsers can use different logic for
|
||||
* computing it.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns suggested filename for this download. It is typically computed by the browser from the
|
||||
* [{@code Content-Disposition}](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) response header
|
||||
* or the {@code download} attribute. See the spec on [whatwg](https://html.spec.whatwg.org/#downloading-resources). Different
|
||||
* browsers can use different logic for computing it.
|
||||
*/
|
||||
String suggestedFilename();
|
||||
/**
|
||||
* Returns downloaded url.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
package com.microsoft.playwright;
|
||||
|
||||
interface Logger {
|
||||
void log(String message);
|
||||
public interface Event<EventType> {
|
||||
EventType type();
|
||||
Object data();
|
||||
}
|
||||
@@ -16,130 +16,70 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code FileChooser} objects are dispatched by the page in the {@link com.microsoft.playwright.Page#onFileChooser
|
||||
* Page.onFileChooser()} event.
|
||||
* <pre>{@code
|
||||
* FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload file").click());
|
||||
* fileChooser.setFiles(Paths.get("myfile.pdf"));
|
||||
* }</pre>
|
||||
* {@code FileChooser} objects are dispatched by the page in the [{@code event: Page.filechooser}] event.
|
||||
*/
|
||||
public interface FileChooser {
|
||||
class FilePayload {
|
||||
public final String name;
|
||||
public final String mimeType;
|
||||
public final byte[] buffer;
|
||||
|
||||
public FilePayload(String name, String mimeType, byte[] buffer) {
|
||||
this.name = name;
|
||||
this.mimeType = mimeType;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
class SetFilesOptions {
|
||||
/**
|
||||
* @deprecated This option has no effect.
|
||||
* Actions that initiate navigations are waiting for these navigations to happen and for pages to start loading. You can
|
||||
* opt out of waiting via setting this flag. You would only need this option in the exceptional cases such as navigating to
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be changed by
|
||||
* using the [{@code method: BrowserContext.setDefaultTimeout}] or [{@code method: Page.setDefaultTimeout}] methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* @deprecated This option has no effect.
|
||||
*/
|
||||
public SetFilesOptions setNoWaitAfter(boolean noWaitAfter) {
|
||||
public SetFilesOptions withNoWaitAfter(boolean noWaitAfter) {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
|
||||
* methods.
|
||||
*/
|
||||
public SetFilesOptions setTimeout(double timeout) {
|
||||
public SetFilesOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns input element associated with this file chooser.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
ElementHandle element();
|
||||
/**
|
||||
* Returns whether this file chooser accepts multiple files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
boolean isMultiple();
|
||||
/**
|
||||
* Returns page this file chooser belongs to.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void setFiles(Path files) {
|
||||
setFiles(files, null);
|
||||
}
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void setFiles(Path files, SetFilesOptions options);
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void setFiles(Path[] files) {
|
||||
setFiles(files, null);
|
||||
}
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void setFiles(Path file) { setFiles(file, null); }
|
||||
default void setFiles(Path file, SetFilesOptions options) { setFiles(new Path[]{ file }, options); }
|
||||
default void setFiles(Path[] files) { setFiles(files, null); }
|
||||
void setFiles(Path[] files, SetFilesOptions options);
|
||||
default void setFiles(FileChooser.FilePayload file) { setFiles(file, null); }
|
||||
default void setFiles(FileChooser.FilePayload file, SetFilesOptions options) { setFiles(new FileChooser.FilePayload[]{ file }, options); }
|
||||
default void setFiles(FileChooser.FilePayload[] files) { setFiles(files, null); }
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
|
||||
* they are resolved relative to the the current working directory. For empty array, clears the selected files.
|
||||
*/
|
||||
default void setFiles(FilePayload files) {
|
||||
setFiles(files, null);
|
||||
}
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void setFiles(FilePayload files, SetFilesOptions options);
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void setFiles(FilePayload[] files) {
|
||||
setFiles(files, null);
|
||||
}
|
||||
/**
|
||||
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
|
||||
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void setFiles(FilePayload[] files, SetFilesOptions options);
|
||||
void setFiles(FileChooser.FilePayload[] files, SetFilesOptions options);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+20
-15
@@ -14,31 +14,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.options;
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public class Geolocation {
|
||||
/**
|
||||
* Latitude between -90 and 90.
|
||||
*/
|
||||
public double latitude;
|
||||
/**
|
||||
* Longitude between -180 and 180.
|
||||
*/
|
||||
public double longitude;
|
||||
/**
|
||||
* Non-negative accuracy value. Defaults to {@code 0}.
|
||||
*/
|
||||
public Double accuracy;
|
||||
|
||||
public Geolocation() {
|
||||
}
|
||||
|
||||
public Geolocation(double latitude, double longitude) {
|
||||
this(latitude, longitude, null);
|
||||
}
|
||||
|
||||
public Geolocation(double latitude, double longitude, Double accuracy) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.accuracy = accuracy;
|
||||
}
|
||||
/**
|
||||
* Non-negative accuracy value. Defaults to {@code 0}.
|
||||
*/
|
||||
public Geolocation setAccuracy(double accuracy) {
|
||||
|
||||
public Geolocation withLatitude(double latitude) {
|
||||
this.latitude = latitude;
|
||||
return this;
|
||||
}
|
||||
public Geolocation withLongitude(double longitude) {
|
||||
this.longitude = longitude;
|
||||
return this;
|
||||
}
|
||||
public Geolocation withAccuracy(double accuracy) {
|
||||
this.accuracy = accuracy;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,147 +19,76 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* JSHandle represents an in-page JavaScript object. JSHandles can be created with the {@link
|
||||
* com.microsoft.playwright.Page#evaluateHandle Page.evaluateHandle()} method.
|
||||
* <pre>{@code
|
||||
* JSHandle windowHandle = page.evaluateHandle("() => window");
|
||||
* // ...
|
||||
* }</pre>
|
||||
* JSHandle represents an in-page JavaScript object. JSHandles can be created with the [{@code method: Page.evaluateHandle}]
|
||||
* method.
|
||||
*
|
||||
* <p> JSHandle prevents the referenced JavaScript object being garbage collected unless the handle is exposed with {@link
|
||||
* com.microsoft.playwright.JSHandle#dispose JSHandle.dispose()}. JSHandles are auto-disposed when their origin frame gets
|
||||
* navigated or the parent context gets destroyed.
|
||||
* <p> JSHandle prevents the referenced JavaScript object being garbage collected unless the handle is exposed with
|
||||
* [{@code method: JSHandle.dispose}]. JSHandles are auto-disposed when their origin frame gets navigated or the parent context
|
||||
* gets destroyed.
|
||||
*
|
||||
* <p> JSHandle instances can be used as an argument in {@link com.microsoft.playwright.Page#evalOnSelector
|
||||
* Page.evalOnSelector()}, {@link com.microsoft.playwright.Page#evaluate Page.evaluate()} and {@link
|
||||
* com.microsoft.playwright.Page#evaluateHandle Page.evaluateHandle()} methods.
|
||||
* <p> JSHandle instances can be used as an argument in [{@code method: Page.$eval}], [{@code method: Page.evaluate}] and
|
||||
* [{@code method: Page.evaluateHandle}] methods.
|
||||
*/
|
||||
public interface JSHandle {
|
||||
/**
|
||||
* Returns either {@code null} or the object handle itself, if the object handle is an instance of {@code ElementHandle}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
ElementHandle asElement();
|
||||
/**
|
||||
* The {@code jsHandle.dispose} method stops referencing the element handle.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void dispose();
|
||||
/**
|
||||
* Returns the return value of {@code expression}.
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
*
|
||||
* <p> If {@code expression} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* handle.evaluate} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* ElementHandle tweetHandle = page.querySelector(".tweet .retweets");
|
||||
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
*/
|
||||
default Object evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
default Object evaluate(String pageFunction) {
|
||||
return evaluate(pageFunction, null);
|
||||
}
|
||||
/**
|
||||
* Returns the return value of {@code expression}.
|
||||
* Returns the return value of {@code pageFunction}
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
* <p> This method passes this handle as the first argument to {@code pageFunction}.
|
||||
*
|
||||
* <p> If {@code expression} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* handle.evaluate} would wait for the promise to resolve and return its value.
|
||||
* <p> If {@code pageFunction} returns a [Promise], then {@code handle.evaluate} would wait for the promise to resolve and return its
|
||||
* value.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* ElementHandle tweetHandle = page.querySelector(".tweet .retweets");
|
||||
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
* @param pageFunction Function to be evaluated in browser context
|
||||
* @param arg Optional argument to pass to {@code pageFunction}
|
||||
*/
|
||||
Object evaluate(String expression, Object arg);
|
||||
/**
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
*
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
|
||||
* jsHandle.evaluateHandle} returns {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> See {@link com.microsoft.playwright.Page#evaluateHandle Page.evaluateHandle()} for more details.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
*/
|
||||
default JSHandle evaluateHandle(String expression) {
|
||||
return evaluateHandle(expression, null);
|
||||
Object evaluate(String pageFunction, Object arg);
|
||||
default JSHandle evaluateHandle(String pageFunction) {
|
||||
return evaluateHandle(pageFunction, null);
|
||||
}
|
||||
/**
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
* Returns the return value of {@code pageFunction} as in-page object (JSHandle).
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
* <p> This method passes this handle as the first argument to {@code pageFunction}.
|
||||
*
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
|
||||
* jsHandle.evaluateHandle} returns {@code JSHandle}.
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code jsHandle.evaluateHandle} returns
|
||||
* in-page object (JSHandle).
|
||||
*
|
||||
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a [Promise], then {@code jsHandle.evaluateHandle} would wait
|
||||
* for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> See {@link com.microsoft.playwright.Page#evaluateHandle Page.evaluateHandle()} for more details.
|
||||
* <p> See [{@code method: Page.evaluateHandle}] for more details.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
* @param pageFunction Function to be evaluated
|
||||
* @param arg Optional argument to pass to {@code pageFunction}
|
||||
*/
|
||||
JSHandle evaluateHandle(String expression, Object arg);
|
||||
JSHandle evaluateHandle(String pageFunction, Object arg);
|
||||
/**
|
||||
* The method returns a map with **own property names** as keys and JSHandle instances for the property values.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* JSHandle handle = page.evaluateHandle("() => ({ window, document })");
|
||||
* Map<String, JSHandle> properties = handle.getProperties();
|
||||
* JSHandle windowHandle = properties.get("window");
|
||||
* JSHandle documentHandle = properties.get("document");
|
||||
* handle.dispose();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Map<String, JSHandle> getProperties();
|
||||
/**
|
||||
* Fetches a single property from the referenced object.
|
||||
*
|
||||
* @param propertyName property to get
|
||||
* @since v1.8
|
||||
*/
|
||||
JSHandle getProperty(String propertyName);
|
||||
/**
|
||||
* Returns a JSON representation of the object. If the object has a {@code toJSON} function, it **will not be called**.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an error if the
|
||||
* object has circular references.
|
||||
*
|
||||
* @since v1.8
|
||||
* <p> <strong>NOTE:</strong> The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an
|
||||
* error if the object has circular references.
|
||||
*/
|
||||
Object jsonValue();
|
||||
}
|
||||
|
||||
@@ -16,52 +16,27 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Keyboard provides an api for managing a virtual keyboard. The high level api is {@link
|
||||
* com.microsoft.playwright.Keyboard#type Keyboard.type()}, which takes raw characters and generates proper {@code
|
||||
* keydown}, {@code keypress}/{@code input}, and {@code keyup} events on your page.
|
||||
* Keyboard provides an api for managing a virtual keyboard. The high level api is [{@code method: Keyboard.type}], which takes
|
||||
* raw characters and generates proper keydown, keypress/input, and keyup events on your page.
|
||||
*
|
||||
* <p> For finer control, you can use {@link com.microsoft.playwright.Keyboard#down Keyboard.down()}, {@link
|
||||
* com.microsoft.playwright.Keyboard#up Keyboard.up()}, and {@link com.microsoft.playwright.Keyboard#insertText
|
||||
* Keyboard.insertText()} to manually fire events as if they were generated from a real keyboard.
|
||||
*
|
||||
* <p> An example of holding down {@code Shift} in order to select and delete some text:
|
||||
* <pre>{@code
|
||||
* page.keyboard().type("Hello World!");
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.keyboard().down("Shift");
|
||||
* for (int i = 0; i < " World".length(); i++)
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.keyboard().up("Shift");
|
||||
* page.keyboard().press("Backspace");
|
||||
* // Result text will end up saying "Hello!"
|
||||
* }</pre>
|
||||
*
|
||||
* <p> An example of pressing uppercase {@code A}
|
||||
* <pre>{@code
|
||||
* page.keyboard().press("Shift+KeyA");
|
||||
* // or
|
||||
* page.keyboard().press("Shift+A");
|
||||
* }</pre>
|
||||
* <p> For finer control, you can use [{@code method: Keyboard.down}], [{@code method: Keyboard.up}], and [{@code method: Keyboard.insertText}]
|
||||
* to manually fire events as if they were generated from a real keyboard.
|
||||
*
|
||||
* <p> An example to trigger select-all with the keyboard
|
||||
* <pre>{@code
|
||||
* page.keyboard().press("ControlOrMeta+A");
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Keyboard {
|
||||
enum Modifier { ALT, CONTROL, META, SHIFT }
|
||||
|
||||
class PressOptions {
|
||||
/**
|
||||
* Time to wait between {@code keydown} and {@code keyup} in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public Double delay;
|
||||
|
||||
/**
|
||||
* Time to wait between {@code keydown} and {@code keyup} in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public PressOptions setDelay(double delay) {
|
||||
public PressOptions withDelay(double delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
@@ -72,10 +47,7 @@ public interface Keyboard {
|
||||
*/
|
||||
public Double delay;
|
||||
|
||||
/**
|
||||
* Time to wait between key presses in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public TypeOptions setDelay(double delay) {
|
||||
public TypeOptions withDelay(double delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
@@ -83,205 +55,83 @@ public interface Keyboard {
|
||||
/**
|
||||
* Dispatches a {@code keydown} event.
|
||||
*
|
||||
* <p> {@code key} can specify the intended <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key">keyboardEvent.key</a> value or a single
|
||||
* character to generate the text for. A superset of the {@code key} values can be found <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
|
||||
* <p> {@code key} can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
|
||||
* value or a single character to generate the text for. A superset of the {@code key} values can be found
|
||||
* [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
|
||||
*
|
||||
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
|
||||
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
|
||||
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
|
||||
* ArrowUp}, etc.
|
||||
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus}, {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab},
|
||||
* {@code Delete}, {@code Escape}, {@code ArrowDown}, {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code ArrowUp}, etc.
|
||||
*
|
||||
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
|
||||
* ShiftLeft}, {@code ControlOrMeta}. {@code ControlOrMeta} resolves to {@code Control} on Windows and Linux and to {@code
|
||||
* Meta} on macOS.
|
||||
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code ShiftLeft}.
|
||||
*
|
||||
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
|
||||
*
|
||||
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
|
||||
* different respective texts.
|
||||
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate different respective
|
||||
* texts.
|
||||
*
|
||||
* <p> If {@code key} is a modifier key, {@code Shift}, {@code Meta}, {@code Control}, or {@code Alt}, subsequent key presses
|
||||
* will be sent with that modifier active. To release the modifier key, use {@link com.microsoft.playwright.Keyboard#up
|
||||
* Keyboard.up()}.
|
||||
* <p> If {@code key} is a modifier key, {@code Shift}, {@code Meta}, {@code Control}, or {@code Alt}, subsequent key presses will be sent with that modifier
|
||||
* active. To release the modifier key, use [{@code method: Keyboard.up}].
|
||||
*
|
||||
* <p> After the key is pressed once, subsequent calls to {@link com.microsoft.playwright.Keyboard#down Keyboard.down()} will
|
||||
* have <a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat">repeat</a> set to true. To release
|
||||
* the key, use {@link com.microsoft.playwright.Keyboard#up Keyboard.up()}.
|
||||
* <p> After the key is pressed once, subsequent calls to [{@code method: Keyboard.down}] will have
|
||||
* [repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat) set to true. To release the key, use
|
||||
* [{@code method: Keyboard.up}].
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO influence {@code keyboard.down}. Holding down {@code Shift} will type the text in upper case.
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
* @since v1.8
|
||||
*/
|
||||
void down(String key);
|
||||
/**
|
||||
* Dispatches only {@code input} event, does not emit the {@code keydown}, {@code keyup} or {@code keypress} events.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.keyboard().insertText("嗨");
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.insertText}. Holding down {@code Shift} will not type the text in upper
|
||||
* case.
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.insertText}. Holding down {@code Shift} will not type the text in upper case.
|
||||
*
|
||||
* @param text Sets input to the specified text value.
|
||||
* @since v1.8
|
||||
*/
|
||||
void insertText(String text);
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link com.microsoft.playwright.Locator#press Locator.press()} instead.
|
||||
*
|
||||
* <p> {@code key} can specify the intended <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key">keyboardEvent.key</a> value or a single
|
||||
* character to generate the text for. A superset of the {@code key} values can be found <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
|
||||
*
|
||||
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
|
||||
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
|
||||
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
|
||||
* ArrowUp}, etc.
|
||||
*
|
||||
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
|
||||
* ShiftLeft}, {@code ControlOrMeta}. {@code ControlOrMeta} resolves to {@code Control} on Windows and Linux and to {@code
|
||||
* Meta} on macOS.
|
||||
*
|
||||
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
|
||||
*
|
||||
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
|
||||
* different respective texts.
|
||||
*
|
||||
* <p> Shortcuts such as {@code key: "Control+o"}, {@code key: "Control++} or {@code key: "Control+Shift+T"} are supported as
|
||||
* well. When specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
* page.keyboard().press("A");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")));
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png")));
|
||||
* page.keyboard().press("Shift+O");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("O.png")));
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Shortcut for {@link com.microsoft.playwright.Keyboard#down Keyboard.down()} and {@link
|
||||
* com.microsoft.playwright.Keyboard#up Keyboard.up()}.
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void press(String key) {
|
||||
press(key, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link com.microsoft.playwright.Locator#press Locator.press()} instead.
|
||||
* {@code key} can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
|
||||
* value or a single character to generate the text for. A superset of the {@code key} values can be found
|
||||
* [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
|
||||
*
|
||||
* <p> {@code key} can specify the intended <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key">keyboardEvent.key</a> value or a single
|
||||
* character to generate the text for. A superset of the {@code key} values can be found <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
|
||||
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus}, {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab},
|
||||
* {@code Delete}, {@code Escape}, {@code ArrowDown}, {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code ArrowUp}, etc.
|
||||
*
|
||||
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
|
||||
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
|
||||
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
|
||||
* ArrowUp}, etc.
|
||||
*
|
||||
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
|
||||
* ShiftLeft}, {@code ControlOrMeta}. {@code ControlOrMeta} resolves to {@code Control} on Windows and Linux and to {@code
|
||||
* Meta} on macOS.
|
||||
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code ShiftLeft}.
|
||||
*
|
||||
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
|
||||
*
|
||||
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
|
||||
* different respective texts.
|
||||
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate different respective
|
||||
* texts.
|
||||
*
|
||||
* <p> Shortcuts such as {@code key: "Control+o"}, {@code key: "Control++} or {@code key: "Control+Shift+T"} are supported as
|
||||
* well. When specified with the modifier, modifier is pressed and being held while the subsequent key is being pressed.
|
||||
* <p> Shortcuts such as {@code key: "Control+o"} or {@code key: "Control+Shift+T"} are supported as well. When speficied with the
|
||||
* modifier, modifier is pressed and being held while the subsequent key is being pressed.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
* page.keyboard().press("A");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")));
|
||||
* page.keyboard().press("ArrowLeft");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png")));
|
||||
* page.keyboard().press("Shift+O");
|
||||
* page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("O.png")));
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Shortcut for {@link com.microsoft.playwright.Keyboard#down Keyboard.down()} and {@link
|
||||
* com.microsoft.playwright.Keyboard#up Keyboard.up()}.
|
||||
* <p> Shortcut for [{@code method: Keyboard.down}] and [{@code method: Keyboard.up}].
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
* @since v1.8
|
||||
*/
|
||||
void press(String key, PressOptions options);
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link com.microsoft.playwright.Locator#fill Locator.fill()} instead. You only need to
|
||||
* press keys one by one if there is special keyboard handling on the page - in this case use {@link
|
||||
* com.microsoft.playwright.Locator#pressSequentially Locator.pressSequentially()}.
|
||||
*
|
||||
* <p> Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
|
||||
*
|
||||
* <p> To press a special key, like {@code Control} or {@code ArrowDown}, use {@link com.microsoft.playwright.Keyboard#press
|
||||
* Keyboard.press()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // Types instantly
|
||||
* page.keyboard().type("Hello");
|
||||
* // Types slower, like a user
|
||||
* page.keyboard().type("World", new Keyboard.TypeOptions().setDelay(100));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.type}. Holding down {@code Shift} will not type the text in upper case.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> For characters that are not on a US keyboard, only an {@code input} event will be sent.
|
||||
*
|
||||
* @param text A text to type into a focused element.
|
||||
* @since v1.8
|
||||
*/
|
||||
void press(String key, PressOptions delay);
|
||||
default void type(String text) {
|
||||
type(text, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link com.microsoft.playwright.Locator#fill Locator.fill()} instead. You only need to
|
||||
* press keys one by one if there is special keyboard handling on the page - in this case use {@link
|
||||
* com.microsoft.playwright.Locator#pressSequentially Locator.pressSequentially()}.
|
||||
* Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
|
||||
*
|
||||
* <p> Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
|
||||
*
|
||||
* <p> To press a special key, like {@code Control} or {@code ArrowDown}, use {@link com.microsoft.playwright.Keyboard#press
|
||||
* Keyboard.press()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // Types instantly
|
||||
* page.keyboard().type("Hello");
|
||||
* // Types slower, like a user
|
||||
* page.keyboard().type("World", new Keyboard.TypeOptions().setDelay(100));
|
||||
* }</pre>
|
||||
* <p> To press a special key, like {@code Control} or {@code ArrowDown}, use [{@code method: Keyboard.press}].
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.type}. Holding down {@code Shift} will not type the text in upper case.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> For characters that are not on a US keyboard, only an {@code input} event will be sent.
|
||||
*
|
||||
* @param text A text to type into a focused element.
|
||||
* @since v1.8
|
||||
*/
|
||||
void type(String text, TypeOptions options);
|
||||
void type(String text, TypeOptions delay);
|
||||
/**
|
||||
* Dispatches a {@code keyup} event.
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
* @since v1.8
|
||||
*/
|
||||
void up(String key);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,34 +16,21 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* page.mouse().move(0, 0);
|
||||
* page.mouse().down();
|
||||
* page.mouse().move(0, 100);
|
||||
* page.mouse().move(100, 100);
|
||||
* page.mouse().move(100, 0);
|
||||
* page.mouse().move(0, 0);
|
||||
* page.mouse().up();
|
||||
* }</pre>
|
||||
* <p> Every {@code page} object has its own Mouse, accessible with [{@code property: Page.mouse}].
|
||||
*/
|
||||
public interface Mouse {
|
||||
enum Button { LEFT, MIDDLE, RIGHT }
|
||||
|
||||
class ClickOptions {
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public MouseButton button;
|
||||
public Button button;
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
@@ -53,24 +40,15 @@ public interface Mouse {
|
||||
*/
|
||||
public Double delay;
|
||||
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public ClickOptions setButton(MouseButton button) {
|
||||
public ClickOptions withButton(Button button) {
|
||||
this.button = button;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
public ClickOptions setClickCount(int clickCount) {
|
||||
public ClickOptions withClickCount(int clickCount) {
|
||||
this.clickCount = clickCount;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to wait between {@code mousedown} and {@code mouseup} in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public ClickOptions setDelay(double delay) {
|
||||
public ClickOptions withDelay(double delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
@@ -79,23 +57,17 @@ public interface Mouse {
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public MouseButton button;
|
||||
public Button button;
|
||||
/**
|
||||
* Time to wait between {@code mousedown} and {@code mouseup} in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public Double delay;
|
||||
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public DblclickOptions setButton(MouseButton button) {
|
||||
public DblclickOptions withButton(Button button) {
|
||||
this.button = button;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to wait between {@code mousedown} and {@code mouseup} in milliseconds. Defaults to 0.
|
||||
*/
|
||||
public DblclickOptions setDelay(double delay) {
|
||||
public DblclickOptions withDelay(double delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
@@ -104,41 +76,28 @@ public interface Mouse {
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public MouseButton button;
|
||||
public Button button;
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
public Integer clickCount;
|
||||
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public DownOptions setButton(MouseButton button) {
|
||||
public DownOptions withButton(Button button) {
|
||||
this.button = button;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
public DownOptions setClickCount(int clickCount) {
|
||||
public DownOptions withClickCount(int clickCount) {
|
||||
this.clickCount = clickCount;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class MoveOptions {
|
||||
/**
|
||||
* Defaults to 1. Sends {@code n} interpolated {@code mousemove} events to represent travel between Playwright's current
|
||||
* cursor position and the provided destination. When set to 1, emits a single {@code mousemove} event at the destination
|
||||
* location.
|
||||
* defaults to 1. Sends intermediate {@code mousemove} events.
|
||||
*/
|
||||
public Integer steps;
|
||||
|
||||
/**
|
||||
* Defaults to 1. Sends {@code n} interpolated {@code mousemove} events to represent travel between Playwright's current
|
||||
* cursor position and the provided destination. When set to 1, emits a single {@code mousemove} event at the destination
|
||||
* location.
|
||||
*/
|
||||
public MoveOptions setSteps(int steps) {
|
||||
public MoveOptions withSteps(int steps) {
|
||||
this.steps = steps;
|
||||
return this;
|
||||
}
|
||||
@@ -147,126 +106,56 @@ public interface Mouse {
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public MouseButton button;
|
||||
public Button button;
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
public Integer clickCount;
|
||||
|
||||
/**
|
||||
* Defaults to {@code left}.
|
||||
*/
|
||||
public UpOptions setButton(MouseButton button) {
|
||||
public UpOptions withButton(Button button) {
|
||||
this.button = button;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* defaults to 1. See [UIEvent.detail].
|
||||
*/
|
||||
public UpOptions setClickCount(int clickCount) {
|
||||
public UpOptions withClickCount(int clickCount) {
|
||||
this.clickCount = clickCount;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void click(double x, double y) {
|
||||
click(x, y, null);
|
||||
}
|
||||
/**
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
* Shortcut for [{@code method: Mouse.move}], [{@code method: Mouse.down}], [{@code method: Mouse.up}].
|
||||
*/
|
||||
void click(double x, double y, ClickOptions options);
|
||||
/**
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()} and {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void dblclick(double x, double y) {
|
||||
dblclick(x, y, null);
|
||||
}
|
||||
/**
|
||||
* Shortcut for {@link com.microsoft.playwright.Mouse#move Mouse.move()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()}, {@link com.microsoft.playwright.Mouse#up Mouse.up()}, {@link com.microsoft.playwright.Mouse#down
|
||||
* Mouse.down()} and {@link com.microsoft.playwright.Mouse#up Mouse.up()}.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
* Shortcut for [{@code method: Mouse.move}], [{@code method: Mouse.down}], [{@code method: Mouse.up}], [{@code method: Mouse.down}] and
|
||||
* [{@code method: Mouse.up}].
|
||||
*/
|
||||
void dblclick(double x, double y, DblclickOptions options);
|
||||
/**
|
||||
* Dispatches a {@code mousedown} event.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void down() {
|
||||
down(null);
|
||||
}
|
||||
/**
|
||||
* Dispatches a {@code mousedown} event.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void down(DownOptions options);
|
||||
/**
|
||||
* Dispatches a {@code mousemove} event.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void move(double x, double y) {
|
||||
move(x, y, null);
|
||||
}
|
||||
/**
|
||||
* Dispatches a {@code mousemove} event.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void move(double x, double y, MoveOptions options);
|
||||
/**
|
||||
* Dispatches a {@code mouseup} event.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void up() {
|
||||
up(null);
|
||||
}
|
||||
/**
|
||||
* Dispatches a {@code mouseup} event.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void up(UpOptions options);
|
||||
/**
|
||||
* Dispatches a {@code wheel} event. This method is usually used to manually scroll the page. See <a
|
||||
* href="https://playwright.dev/java/docs/input#scrolling">scrolling</a> for alternative ways to scroll.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Wheel events may cause scrolling if they are not handled, and this method does not wait for the scrolling to finish
|
||||
* before returning.
|
||||
*
|
||||
* @param deltaX Pixels to scroll horizontally.
|
||||
* @param deltaY Pixels to scroll vertically.
|
||||
* @since v1.15
|
||||
*/
|
||||
void wheel(double deltaX, double deltaY);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,96 +22,34 @@ import java.util.*;
|
||||
/**
|
||||
* Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright
|
||||
* to drive automation:
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.*;
|
||||
*
|
||||
* public class Example {
|
||||
* public static void main(String[] args) {
|
||||
* try (Playwright playwright = Playwright.create()) {
|
||||
* BrowserType chromium = playwright.chromium();
|
||||
* Browser browser = chromium.launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("http://example.com");
|
||||
* // other actions...
|
||||
* browser.close();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Playwright extends AutoCloseable {
|
||||
class CreateOptions {
|
||||
/**
|
||||
* Additional environment variables that will be passed to the driver process. By default driver process inherits
|
||||
* environment variables of the Playwright process.
|
||||
*/
|
||||
public Map<String, String> env;
|
||||
|
||||
/**
|
||||
* Additional environment variables that will be passed to the driver process. By default driver process inherits
|
||||
* environment variables of the Playwright process.
|
||||
*/
|
||||
public CreateOptions setEnv(Map<String, String> env) {
|
||||
this.env = env;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
public interface Playwright {
|
||||
/**
|
||||
* This object can be used to launch or connect to Chromium, returning instances of {@code Browser}.
|
||||
*
|
||||
* @since v1.8
|
||||
* This object can be used to launch or connect to Chromium, returning instances of {@code ChromiumBrowser}.
|
||||
*/
|
||||
BrowserType chromium();
|
||||
/**
|
||||
* This object can be used to launch or connect to Firefox, returning instances of {@code Browser}.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns a dictionary of devices to be used with [{@code method: Browser.newContext}] or [{@code method: Browser.newPage}].
|
||||
*/
|
||||
Map<String, DeviceDescriptor> devices();
|
||||
/**
|
||||
* This object can be used to launch or connect to Firefox, returning instances of {@code FirefoxBrowser}.
|
||||
*/
|
||||
BrowserType firefox();
|
||||
/**
|
||||
* Exposes API that can be used for the Web API testing.
|
||||
*
|
||||
* @since v1.16
|
||||
*/
|
||||
APIRequest request();
|
||||
/**
|
||||
* Selectors can be used to install custom selector engines. See <a
|
||||
* href="https://playwright.dev/java/docs/extensibility">extensibility</a> for more information.
|
||||
*
|
||||
* @since v1.8
|
||||
* Selectors can be used to install custom selector engines. See
|
||||
* [Working with selectors](./selectors.md#working-with-selectors) for more information.
|
||||
*/
|
||||
Selectors selectors();
|
||||
/**
|
||||
* This object can be used to launch or connect to WebKit, returning instances of {@code Browser}.
|
||||
*
|
||||
* @since v1.8
|
||||
* This object can be used to launch or connect to WebKit, returning instances of {@code WebKitBrowser}.
|
||||
*/
|
||||
BrowserType webkit();
|
||||
/**
|
||||
* Terminates this instance of Playwright, will also close all created browsers if they are still running.
|
||||
*
|
||||
* @since v1.9
|
||||
*/
|
||||
void close();
|
||||
/**
|
||||
* Launches new Playwright driver process and connects to it. {@link com.microsoft.playwright.Playwright#close
|
||||
* Playwright.close()} should be called when the instance is no longer needed.
|
||||
* <pre>{@code
|
||||
* Playwright playwright = Playwright.create();
|
||||
* Browser browser = playwright.webkit().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://www.w3.org/");
|
||||
* playwright.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.10
|
||||
*/
|
||||
static Playwright create(CreateOptions options) {
|
||||
return PlaywrightImpl.create(options);
|
||||
}
|
||||
|
||||
static Playwright create() {
|
||||
return create(null);
|
||||
return PlaywrightImpl.create();
|
||||
}
|
||||
|
||||
void close() throws Exception;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
/**
|
||||
* PlaywrightException is thrown whenever certain operations are terminated abnormally, e.g. browser closes while {@link
|
||||
* Page#evaluate Page.evaluate()} is running. All Playwright exceptions inherit from this class.
|
||||
*/
|
||||
public class PlaywrightException extends RuntimeException {
|
||||
public PlaywrightException(String message) {
|
||||
super(message);
|
||||
|
||||
+17
-5
@@ -14,14 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.options;
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public class Position {
|
||||
public double x;
|
||||
public double y;
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public Position(double x, double y) {
|
||||
public Position() {
|
||||
}
|
||||
|
||||
public Position(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
public Position withX(int x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
public Position withY(int y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -16,210 +16,177 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Whenever the page sends a request for a network resource the following sequence of events are emitted by {@code Page}:
|
||||
* <ul>
|
||||
* <li> {@link com.microsoft.playwright.Page#onRequest Page.onRequest()} emitted when the request is issued by the page.</li>
|
||||
* <li> {@link com.microsoft.playwright.Page#onResponse Page.onResponse()} emitted when/if the response status and headers are
|
||||
* received for the request.</li>
|
||||
* <li> {@link com.microsoft.playwright.Page#onRequestFinished Page.onRequestFinished()} emitted when the response body is
|
||||
* downloaded and the request is complete.</li>
|
||||
* </ul>
|
||||
* - [{@code event: Page.request}] emitted when the request is issued by the page.
|
||||
* - [{@code event: Page.response}] emitted when/if the response status and headers are received for the request.
|
||||
* - [{@code event: Page.requestfinished}] emitted when the response body is downloaded and the request is complete.
|
||||
*
|
||||
* <p> If request fails at some point, then instead of {@code "requestfinished"} event (and possibly instead of 'response'
|
||||
* event), the {@link com.microsoft.playwright.Page#onRequestFailed Page.onRequestFailed()} event is emitted.
|
||||
* <p> If request fails at some point, then instead of {@code 'requestfinished'} event (and possibly instead of 'response' event),
|
||||
* the [{@code event: Page.requestfailed}] event is emitted.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will complete
|
||||
* with {@code "requestfinished"} event.
|
||||
* <p> <strong>NOTE:</strong> HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will
|
||||
* complete with {@code 'requestfinished'} event.
|
||||
*
|
||||
* <p> If request gets a 'redirect' response, the request is successfully finished with the {@code requestfinished} event, and
|
||||
* a new request is issued to a redirected url.
|
||||
* <p> If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new
|
||||
* request is issued to a redirected url.
|
||||
*/
|
||||
public interface Request {
|
||||
/**
|
||||
* An object with all the request HTTP headers associated with this request. The header names are lower-cased.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
Map<String, String> allHeaders();
|
||||
class RequestFailure {
|
||||
/**
|
||||
* Human-readable error message, e.g. {@code 'net::ERR_FAILED'}.
|
||||
*/
|
||||
private String errorText;
|
||||
|
||||
public RequestFailure(String errorText) {
|
||||
this.errorText = errorText;
|
||||
}
|
||||
public String errorText() {
|
||||
return this.errorText;
|
||||
}
|
||||
}
|
||||
class RequestTiming {
|
||||
/**
|
||||
* Request start time in milliseconds elapsed since January 1, 1970 00:00:00 UTC
|
||||
*/
|
||||
private double startTime;
|
||||
/**
|
||||
* Time immediately before the browser starts the domain name lookup for the resource. The value is given in milliseconds
|
||||
* relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double domainLookupStart;
|
||||
/**
|
||||
* Time immediately after the browser starts the domain name lookup for the resource. The value is given in milliseconds
|
||||
* relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double domainLookupEnd;
|
||||
/**
|
||||
* Time immediately before the user agent starts establishing the connection to the server to retrieve the resource. The
|
||||
* value is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double connectStart;
|
||||
/**
|
||||
* Time immediately before the browser starts the handshake process to secure the current connection. The value is given in
|
||||
* milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double secureConnectionStart;
|
||||
/**
|
||||
* Time immediately before the user agent starts establishing the connection to the server to retrieve the resource. The
|
||||
* value is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double connectEnd;
|
||||
/**
|
||||
* Time immediately before the browser starts requesting the resource from the server, cache, or local resource. The value
|
||||
* is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double requestStart;
|
||||
/**
|
||||
* Time immediately after the browser starts requesting the resource from the server, cache, or local resource. The value
|
||||
* is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double responseStart;
|
||||
/**
|
||||
* Time immediately after the browser receives the last byte of the resource or immediately before the transport connection
|
||||
* is closed, whichever comes first. The value is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
private double responseEnd;
|
||||
|
||||
public double startTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
public double domainLookupStart() {
|
||||
return this.domainLookupStart;
|
||||
}
|
||||
public double domainLookupEnd() {
|
||||
return this.domainLookupEnd;
|
||||
}
|
||||
public double connectStart() {
|
||||
return this.connectStart;
|
||||
}
|
||||
public double secureConnectionStart() {
|
||||
return this.secureConnectionStart;
|
||||
}
|
||||
public double connectEnd() {
|
||||
return this.connectEnd;
|
||||
}
|
||||
public double requestStart() {
|
||||
return this.requestStart;
|
||||
}
|
||||
public double responseStart() {
|
||||
return this.responseStart;
|
||||
}
|
||||
public double responseEnd() {
|
||||
return this.responseEnd;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The method returns {@code null} unless this request has failed, as reported by {@code requestfailed} event.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> Example of logging of all the failed requests:
|
||||
* <pre>{@code
|
||||
* page.onRequestFailed(request -> {
|
||||
* System.out.println(request.url() + " " + request.failure());
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String failure();
|
||||
RequestFailure failure();
|
||||
/**
|
||||
* Returns the {@code Frame} that initiated this request.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* String frameUrl = request.frame().url();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> Note that in some cases the frame is not available, and this method will throw.
|
||||
* <ul>
|
||||
* <li> When request originates in the Service Worker. You can use {@code request.serviceWorker()} to check that.</li>
|
||||
* <li> When navigation request is issued before the corresponding frame is created. You can use {@link
|
||||
* com.microsoft.playwright.Request#isNavigationRequest Request.isNavigationRequest()} to check that.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Here is an example that handles all the cases:
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Frame frame();
|
||||
/**
|
||||
* An object with the request HTTP headers. The header names are lower-cased. Note that this method does not return
|
||||
* security-related headers, including cookie-related ones. You can use {@link com.microsoft.playwright.Request#allHeaders
|
||||
* Request.allHeaders()} for complete list of headers that include {@code cookie} information.
|
||||
*
|
||||
* @since v1.8
|
||||
* An object with HTTP headers associated with the request. All header names are lower-case.
|
||||
*/
|
||||
Map<String, String> headers();
|
||||
/**
|
||||
* An array with all the request HTTP headers associated with this request. Unlike {@link
|
||||
* com.microsoft.playwright.Request#allHeaders Request.allHeaders()}, header names are NOT lower-cased. Headers with
|
||||
* multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
List<HttpHeader> headersArray();
|
||||
/**
|
||||
* Returns the value of the header matching the name. The name is case-insensitive.
|
||||
*
|
||||
* @param name Name of the header.
|
||||
* @since v1.15
|
||||
*/
|
||||
String headerValue(String name);
|
||||
/**
|
||||
* Whether this request is driving frame's navigation.
|
||||
*
|
||||
* <p> Some navigation requests are issued before the corresponding frame is created, and therefore do not have {@link
|
||||
* com.microsoft.playwright.Request#frame Request.frame()} available.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
boolean isNavigationRequest();
|
||||
/**
|
||||
* Request's method (GET, POST, etc.)
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String method();
|
||||
/**
|
||||
* Request's post body, if any.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String postData();
|
||||
/**
|
||||
* Request's post body in a binary form, if any.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
byte[] postDataBuffer();
|
||||
/**
|
||||
* Request that was redirected by the server to this one, if any.
|
||||
*
|
||||
* <p> When the server responds with a redirect, Playwright creates a new {@code Request} object. The two requests are
|
||||
* connected by {@code redirectedFrom()} and {@code redirectedTo()} methods. When multiple server redirects has happened,
|
||||
* it is possible to construct the whole redirect chain by repeatedly calling {@code redirectedFrom()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <p> When the server responds with a redirect, Playwright creates a new {@code Request} object. The two requests are connected by
|
||||
* {@code redirectedFrom()} and {@code redirectedTo()} methods. When multiple server redirects has happened, it is possible to
|
||||
* construct the whole redirect chain by repeatedly calling {@code redirectedFrom()}.
|
||||
*
|
||||
* <p> For example, if the website {@code http://example.com} redirects to {@code https://example.com}:
|
||||
* <pre>{@code
|
||||
* Response response = page.navigate("http://example.com");
|
||||
* System.out.println(response.request().redirectedFrom().url()); // "http://example.com"
|
||||
* }</pre>
|
||||
*
|
||||
* <p> If the website {@code https://google.com} has no redirects:
|
||||
* <pre>{@code
|
||||
* Response response = page.navigate("https://google.com");
|
||||
* System.out.println(response.request().redirectedFrom()); // null
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Request redirectedFrom();
|
||||
/**
|
||||
* New request issued by the browser if the server responded with redirect.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> This method is the opposite of {@link com.microsoft.playwright.Request#redirectedFrom Request.redirectedFrom()}:
|
||||
* <pre>{@code
|
||||
* System.out.println(request.redirectedFrom().redirectedTo() == request); // true
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
* <p> This method is the opposite of [{@code method: Request.redirectedFrom}]:
|
||||
*/
|
||||
Request redirectedTo();
|
||||
/**
|
||||
* Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
|
||||
* following: {@code document}, {@code stylesheet}, {@code image}, {@code media}, {@code font}, {@code script}, {@code
|
||||
* texttrack}, {@code xhr}, {@code fetch}, {@code eventsource}, {@code websocket}, {@code manifest}, {@code other}.
|
||||
*
|
||||
* @since v1.8
|
||||
* following: {@code document}, {@code stylesheet}, {@code image}, {@code media}, {@code font}, {@code script}, {@code texttrack}, {@code xhr}, {@code fetch}, {@code eventsource},
|
||||
* {@code websocket}, {@code manifest}, {@code other}.
|
||||
*/
|
||||
String resourceType();
|
||||
/**
|
||||
* Returns the matching {@code Response} object, or {@code null} if the response was not received due to error.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Response response();
|
||||
/**
|
||||
* Returns the {@code Response} object if the response has already been received, {@code null} otherwise.
|
||||
*
|
||||
* <p> Unlike {@link com.microsoft.playwright.Request#response Request.response()}, this method does not wait for the response
|
||||
* to arrive. It returns immediately with the response object if the response has been received, or {@code null} if the
|
||||
* response has not been received yet.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
Response existingResponse();
|
||||
/**
|
||||
* Returns resource size information for given request.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
Sizes sizes();
|
||||
/**
|
||||
* Returns resource timing information for given request. Most of the timing values become available upon the response,
|
||||
* {@code responseEnd} becomes available when request finishes. Find more information at <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming">Resource Timing API</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.onRequestFinished(request -> {
|
||||
* Timing timing = request.timing();
|
||||
* System.out.println(timing.responseEnd - timing.startTime);
|
||||
* });
|
||||
* page.navigate("http://example.com");
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
* {@code responseEnd} becomes available when request finishes. Find more information at
|
||||
* [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).
|
||||
*/
|
||||
Timing timing();
|
||||
RequestTiming timing();
|
||||
/**
|
||||
* URL of the request.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
@@ -16,128 +16,50 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code Response} class represents responses which are received by page.
|
||||
*/
|
||||
public interface Response {
|
||||
/**
|
||||
* An object with all the response HTTP headers associated with this response.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
Map<String, String> allHeaders();
|
||||
/**
|
||||
* Returns the buffer with response body.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
byte[] body();
|
||||
/**
|
||||
* Waits for this response to finish, returns always {@code null}.
|
||||
*
|
||||
* @since v1.8
|
||||
* Waits for this response to finish, returns failure error if request failed.
|
||||
*/
|
||||
String finished();
|
||||
/**
|
||||
* Returns the {@code Frame} that initiated this response.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Frame frame();
|
||||
/**
|
||||
* Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith">FetchEvent.respondWith</a>).
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
boolean fromServiceWorker();
|
||||
/**
|
||||
* An object with the response HTTP headers. The header names are lower-cased. Note that this method does not return
|
||||
* security-related headers, including cookie-related ones. You can use {@link com.microsoft.playwright.Response#allHeaders
|
||||
* Response.allHeaders()} for complete list of headers that include {@code cookie} information.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns the object with HTTP headers associated with the response. All header names are lower-case.
|
||||
*/
|
||||
Map<String, String> headers();
|
||||
/**
|
||||
* An array with all the request HTTP headers associated with this response. Unlike {@link
|
||||
* com.microsoft.playwright.Response#allHeaders Response.allHeaders()}, header names are NOT lower-cased. Headers with
|
||||
* multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
List<HttpHeader> headersArray();
|
||||
/**
|
||||
* Returns the value of the header matching the name. The name is case-insensitive. If multiple headers have the same name
|
||||
* (except {@code set-cookie}), they are returned as a list separated by {@code , }. For {@code set-cookie}, the {@code \n}
|
||||
* separator is used. If no headers are found, {@code null} is returned.
|
||||
*
|
||||
* @param name Name of the header.
|
||||
* @since v1.15
|
||||
*/
|
||||
String headerValue(String name);
|
||||
/**
|
||||
* Returns all values of the headers matching the name, for example {@code set-cookie}. The name is case-insensitive.
|
||||
*
|
||||
* @param name Name of the header.
|
||||
* @since v1.15
|
||||
*/
|
||||
List<String> headerValues(String name);
|
||||
/**
|
||||
* Returns the http version used by the response.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
String httpVersion();
|
||||
/**
|
||||
* Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
boolean ok();
|
||||
/**
|
||||
* Returns the matching {@code Request} object.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Request request();
|
||||
/**
|
||||
* Returns SSL and other security information.
|
||||
*
|
||||
* @since v1.13
|
||||
*/
|
||||
SecurityDetails securityDetails();
|
||||
/**
|
||||
* Returns the IP address and port of the server.
|
||||
*
|
||||
* @since v1.13
|
||||
*/
|
||||
ServerAddr serverAddr();
|
||||
/**
|
||||
* Contains the status code of the response (e.g., 200 for a success).
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
int status();
|
||||
/**
|
||||
* Contains the status text of the response (e.g. usually an "OK" for a success).
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String statusText();
|
||||
/**
|
||||
* Returns the text representation of response body.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String text();
|
||||
/**
|
||||
* Contains the URL of the response.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
@@ -16,228 +16,59 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Whenever a network route is set up with {@link com.microsoft.playwright.Page#route Page.route()} or {@link
|
||||
* com.microsoft.playwright.BrowserContext#route BrowserContext.route()}, the {@code Route} object allows to handle the
|
||||
* route.
|
||||
*
|
||||
* <p> Learn more about <a href="https://playwright.dev/java/docs/network">networking</a>.
|
||||
* Whenever a network route is set up with [{@code method: Page.route}] or [{@code method: BrowserContext.route}], the {@code Route} object
|
||||
* allows to handle the route.
|
||||
*/
|
||||
public interface Route {
|
||||
class ResumeOptions {
|
||||
class ContinueOptions {
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
* If set changes the request method (e.g. GET or POST)
|
||||
*/
|
||||
public String method;
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
* If set changes the post data of request
|
||||
*/
|
||||
public Object postData;
|
||||
public byte[] postData;
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one.
|
||||
*/
|
||||
public String url;
|
||||
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public ResumeOptions setHeaders(Map<String, String> headers) {
|
||||
public ContinueOptions withHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public ResumeOptions setMethod(String method) {
|
||||
public ContinueOptions withMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public ResumeOptions setPostData(String postData) {
|
||||
public ContinueOptions withPostData(String postData) {
|
||||
this.postData = postData.getBytes(StandardCharsets.UTF_8);
|
||||
return this;
|
||||
}
|
||||
public ContinueOptions withPostData(byte[] postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public ResumeOptions setPostData(byte[] postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one.
|
||||
*/
|
||||
public ResumeOptions setUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FallbackOptions {
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public String method;
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public Object postData;
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the route
|
||||
* matching, all the routes are matched using the original request URL.
|
||||
*/
|
||||
public String url;
|
||||
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public FallbackOptions setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public FallbackOptions setMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FallbackOptions setPostData(String postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FallbackOptions setPostData(byte[] postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one. Changing the URL won't affect the route
|
||||
* matching, all the routes are matched using the original request URL.
|
||||
*/
|
||||
public FallbackOptions setUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FetchOptions {
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
|
||||
*/
|
||||
public Integer maxRedirects;
|
||||
/**
|
||||
* Maximum number of times network errors should be retried. Currently only {@code ECONNRESET} error is retried. Does not
|
||||
* retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to {@code 0} - no
|
||||
* retries.
|
||||
*/
|
||||
public Integer maxRetries;
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public String method;
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public Object postData;
|
||||
/**
|
||||
* Request timeout in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one.
|
||||
*/
|
||||
public String url;
|
||||
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public FetchOptions setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
|
||||
*/
|
||||
public FetchOptions setMaxRedirects(int maxRedirects) {
|
||||
this.maxRedirects = maxRedirects;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum number of times network errors should be retried. Currently only {@code ECONNRESET} error is retried. Does not
|
||||
* retry based on HTTP response codes. An error will be thrown if the limit is exceeded. Defaults to {@code 0} - no
|
||||
* retries.
|
||||
*/
|
||||
public FetchOptions setMaxRetries(int maxRetries) {
|
||||
this.maxRetries = maxRetries;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public FetchOptions setMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FetchOptions setPostData(String postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FetchOptions setPostData(byte[] postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Request timeout in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public FetchOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one.
|
||||
*/
|
||||
public FetchOptions setUrl(String url) {
|
||||
public ContinueOptions withUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FulfillOptions {
|
||||
/**
|
||||
* Optional response body as text.
|
||||
* Response body.
|
||||
*/
|
||||
public String body;
|
||||
/**
|
||||
* Optional response body as raw bytes.
|
||||
*/
|
||||
public byte[] bodyBytes;
|
||||
/**
|
||||
* If set, equals to setting {@code Content-Type} response header.
|
||||
@@ -248,77 +79,40 @@ public interface Route {
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path,
|
||||
* then it is resolved relative to the current working directory.
|
||||
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path, then it
|
||||
* is resolved relative to the current working directory.
|
||||
*/
|
||||
public Path path;
|
||||
/**
|
||||
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be
|
||||
* overridden using fulfill options.
|
||||
*/
|
||||
public APIResponse response;
|
||||
/**
|
||||
* Response status code, defaults to {@code 200}.
|
||||
*/
|
||||
public Integer status;
|
||||
|
||||
/**
|
||||
* Optional response body as text.
|
||||
*/
|
||||
public FulfillOptions setBody(String body) {
|
||||
public FulfillOptions withBody(byte[] body) {
|
||||
this.bodyBytes = body;
|
||||
return this;
|
||||
}
|
||||
public FulfillOptions withBody(String body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Optional response body as raw bytes.
|
||||
*/
|
||||
public FulfillOptions setBodyBytes(byte[] bodyBytes) {
|
||||
this.bodyBytes = bodyBytes;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set, equals to setting {@code Content-Type} response header.
|
||||
*/
|
||||
public FulfillOptions setContentType(String contentType) {
|
||||
public FulfillOptions withContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Response headers. Header values will be converted to a string.
|
||||
*/
|
||||
public FulfillOptions setHeaders(Map<String, String> headers) {
|
||||
public FulfillOptions withHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path,
|
||||
* then it is resolved relative to the current working directory.
|
||||
*/
|
||||
public FulfillOptions setPath(Path path) {
|
||||
public FulfillOptions withPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be
|
||||
* overridden using fulfill options.
|
||||
*/
|
||||
public FulfillOptions setResponse(APIResponse response) {
|
||||
this.response = response;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Response status code, defaults to {@code 200}.
|
||||
*/
|
||||
public FulfillOptions setStatus(int status) {
|
||||
public FulfillOptions withStatus(int status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Aborts the route's request.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void abort() {
|
||||
abort(null);
|
||||
}
|
||||
@@ -326,339 +120,40 @@ public interface Route {
|
||||
* Aborts the route's request.
|
||||
*
|
||||
* @param errorCode Optional error code. Defaults to {@code failed}, could be one of the following:
|
||||
* <ul>
|
||||
* <li> {@code "aborted"} - An operation was aborted (due to user action)</li>
|
||||
* <li> {@code "accessdenied"} - Permission to access a resource, other than the network, was denied</li>
|
||||
* <li> {@code "addressunreachable"} - The IP address is unreachable. This usually means that there is no route to the specified
|
||||
* host or network.</li>
|
||||
* <li> {@code "blockedbyclient"} - The client chose to block the request.</li>
|
||||
* <li> {@code "blockedbyresponse"} - The request failed because the response was delivered along with requirements which are
|
||||
* not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).</li>
|
||||
* <li> {@code "connectionaborted"} - A connection timed out as a result of not receiving an ACK for data sent.</li>
|
||||
* <li> {@code "connectionclosed"} - A connection was closed (corresponding to a TCP FIN).</li>
|
||||
* <li> {@code "connectionfailed"} - A connection attempt failed.</li>
|
||||
* <li> {@code "connectionrefused"} - A connection attempt was refused.</li>
|
||||
* <li> {@code "connectionreset"} - A connection was reset (corresponding to a TCP RST).</li>
|
||||
* <li> {@code "internetdisconnected"} - The Internet connection has been lost.</li>
|
||||
* <li> {@code "namenotresolved"} - The host name could not be resolved.</li>
|
||||
* <li> {@code "timedout"} - An operation timed out.</li>
|
||||
* <li> {@code "failed"} - A generic failure occurred.</li>
|
||||
* </ul>
|
||||
* @since v1.8
|
||||
* - {@code 'aborted'} - An operation was aborted (due to user action)
|
||||
* - {@code 'accessdenied'} - Permission to access a resource, other than the network, was denied
|
||||
* - {@code 'addressunreachable'} - The IP address is unreachable. This usually means that there is no route to the specified
|
||||
* host or network.
|
||||
* - {@code 'blockedbyclient'} - The client chose to block the request.
|
||||
* - {@code 'blockedbyresponse'} - The request failed because the response was delivered along with requirements which are not
|
||||
* met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).
|
||||
* - {@code 'connectionaborted'} - A connection timed out as a result of not receiving an ACK for data sent.
|
||||
* - {@code 'connectionclosed'} - A connection was closed (corresponding to a TCP FIN).
|
||||
* - {@code 'connectionfailed'} - A connection attempt failed.
|
||||
* - {@code 'connectionrefused'} - A connection attempt was refused.
|
||||
* - {@code 'connectionreset'} - A connection was reset (corresponding to a TCP RST).
|
||||
* - {@code 'internetdisconnected'} - The Internet connection has been lost.
|
||||
* - {@code 'namenotresolved'} - The host name could not be resolved.
|
||||
* - {@code 'timedout'} - An operation timed out.
|
||||
* - {@code 'failed'} - A generic failure occurred.
|
||||
*/
|
||||
void abort(String errorCode);
|
||||
/**
|
||||
* Sends route's request to the network with optional overrides.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Override headers
|
||||
* Map<String, String> headers = new HashMap<>(route.request().headers());
|
||||
* headers.put("foo", "foo-value"); // set "foo" header
|
||||
* headers.remove("bar"); // remove "bar" header
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url},
|
||||
* {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests.
|
||||
*
|
||||
* <p> {@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other
|
||||
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
|
||||
* next matching handler in the chain to be invoked.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Some request headers are **forbidden** and cannot be overridden (for example, {@code Cookie}, {@code Host}, {@code
|
||||
* Content-Length} and others, see <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header">this MDN page</a> for full list). If
|
||||
* an override is provided for a forbidden header, it will be ignored and the original request header will be used.To set custom cookies, use {@link com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void resume() {
|
||||
resume(null);
|
||||
default void continue_() {
|
||||
continue_(null);
|
||||
}
|
||||
/**
|
||||
* Sends route's request to the network with optional overrides.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Override headers
|
||||
* Map<String, String> headers = new HashMap<>(route.request().headers());
|
||||
* headers.put("foo", "foo-value"); // set "foo" header
|
||||
* headers.remove("bar"); // remove "bar" header
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url},
|
||||
* {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests.
|
||||
*
|
||||
* <p> {@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other
|
||||
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
|
||||
* next matching handler in the chain to be invoked.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Some request headers are **forbidden** and cannot be overridden (for example, {@code Cookie}, {@code Host}, {@code
|
||||
* Content-Length} and others, see <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header">this MDN page</a> for full list). If
|
||||
* an override is provided for a forbidden header, it will be ignored and the original request header will be used.To set custom cookies, use {@link com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void resume(ResumeOptions options);
|
||||
/**
|
||||
* Continues route's request with optional overrides. The method is similar to {@link com.microsoft.playwright.Route#resume
|
||||
* Route.resume()} with the difference that other matching handlers will be invoked before sending the request.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* registered route can always override all the previous ones. In the example below, request will be handled by the
|
||||
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
|
||||
* registered route.
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs last.
|
||||
* route.abort();
|
||||
* });
|
||||
*
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs second.
|
||||
* route.fallback();
|
||||
* });
|
||||
*
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs first.
|
||||
* route.fallback();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Registering multiple routes is useful when you want separate handlers to handle different kinds of requests, for example
|
||||
* API calls vs page resources or GET requests vs POST requests as in the example below.
|
||||
* <pre>{@code
|
||||
* // Handle GET requests.
|
||||
* page.route("**\/*", route -> {
|
||||
* if (!route.request().method().equals("GET")) {
|
||||
* route.fallback();
|
||||
* return;
|
||||
* }
|
||||
* // Handling GET only.
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* // Handle POST requests.
|
||||
* page.route("**\/*", route -> {
|
||||
* if (!route.request().method().equals("POST")) {
|
||||
* route.fallback();
|
||||
* return;
|
||||
* }
|
||||
* // Handling POST only.
|
||||
* // ...
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> One can also modify request while falling back to the subsequent handler, that way intermediate route handler can modify
|
||||
* url, method, headers and postData of the request.
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Override headers
|
||||
* Map<String, String> headers = new HashMap<>(route.request().headers());
|
||||
* headers.put("foo", "foo-value"); // set "foo" header
|
||||
* headers.remove("bar"); // remove "bar" header
|
||||
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Use {@link com.microsoft.playwright.Route#resume Route.resume()} to immediately send the request to the network, other
|
||||
* matching handlers won't be invoked in that case.
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
default void fallback() {
|
||||
fallback(null);
|
||||
}
|
||||
/**
|
||||
* Continues route's request with optional overrides. The method is similar to {@link com.microsoft.playwright.Route#resume
|
||||
* Route.resume()} with the difference that other matching handlers will be invoked before sending the request.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> When several routes match the given pattern, they run in the order opposite to their registration. That way the last
|
||||
* registered route can always override all the previous ones. In the example below, request will be handled by the
|
||||
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
|
||||
* registered route.
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs last.
|
||||
* route.abort();
|
||||
* });
|
||||
*
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs second.
|
||||
* route.fallback();
|
||||
* });
|
||||
*
|
||||
* page.route("**\/*", route -> {
|
||||
* // Runs first.
|
||||
* route.fallback();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Registering multiple routes is useful when you want separate handlers to handle different kinds of requests, for example
|
||||
* API calls vs page resources or GET requests vs POST requests as in the example below.
|
||||
* <pre>{@code
|
||||
* // Handle GET requests.
|
||||
* page.route("**\/*", route -> {
|
||||
* if (!route.request().method().equals("GET")) {
|
||||
* route.fallback();
|
||||
* return;
|
||||
* }
|
||||
* // Handling GET only.
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* // Handle POST requests.
|
||||
* page.route("**\/*", route -> {
|
||||
* if (!route.request().method().equals("POST")) {
|
||||
* route.fallback();
|
||||
* return;
|
||||
* }
|
||||
* // Handling POST only.
|
||||
* // ...
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> One can also modify request while falling back to the subsequent handler, that way intermediate route handler can modify
|
||||
* url, method, headers and postData of the request.
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Override headers
|
||||
* Map<String, String> headers = new HashMap<>(route.request().headers());
|
||||
* headers.put("foo", "foo-value"); // set "foo" header
|
||||
* headers.remove("bar"); // remove "bar" header
|
||||
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Use {@link com.microsoft.playwright.Route#resume Route.resume()} to immediately send the request to the network, other
|
||||
* matching handlers won't be invoked in that case.
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
void fallback(FallbackOptions options);
|
||||
/**
|
||||
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
|
||||
* fulfilled.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
|
||||
* APIResponse response = route.fetch();
|
||||
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
|
||||
* JsonObject message = itemObj.get("json").getAsJsonObject();
|
||||
* message.set("big_red_dog", new JsonArray());
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setResponse(response)
|
||||
* .setBody(json.toString()));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
|
||||
* to only apply {@code headers} to the original request, but not to redirects, look into {@link
|
||||
* com.microsoft.playwright.Route#resume Route.resume()} instead.
|
||||
*
|
||||
* @since v1.29
|
||||
*/
|
||||
default APIResponse fetch() {
|
||||
return fetch(null);
|
||||
}
|
||||
/**
|
||||
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
|
||||
* fulfilled.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
|
||||
* APIResponse response = route.fetch();
|
||||
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
|
||||
* JsonObject message = itemObj.get("json").getAsJsonObject();
|
||||
* message.set("big_red_dog", new JsonArray());
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setResponse(response)
|
||||
* .setBody(json.toString()));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Details</strong>
|
||||
*
|
||||
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
|
||||
* to only apply {@code headers} to the original request, but not to redirects, look into {@link
|
||||
* com.microsoft.playwright.Route#resume Route.resume()} instead.
|
||||
*
|
||||
* @since v1.29
|
||||
*/
|
||||
APIResponse fetch(FetchOptions options);
|
||||
/**
|
||||
* Fulfills route's request with given response.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of fulfilling all requests with 404 responses:
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setStatus(404)
|
||||
* .setContentType("text/plain")
|
||||
* .setBody("Not Found!"));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> An example of serving static file:
|
||||
* <pre>{@code
|
||||
* page.route("**\/xhr_endpoint", route -> route.fulfill(
|
||||
* new Route.FulfillOptions().setPath(Paths.get("mock_data.json"))));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
* Continues route's request with optional overrides.
|
||||
*/
|
||||
void continue_(ContinueOptions options);
|
||||
default void fulfill() {
|
||||
fulfill(null);
|
||||
}
|
||||
/**
|
||||
* Fulfills route's request with given response.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of fulfilling all requests with 404 responses:
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setStatus(404)
|
||||
* .setContentType("text/plain")
|
||||
* .setBody("Not Found!"));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> An example of serving static file:
|
||||
* <pre>{@code
|
||||
* page.route("**\/xhr_endpoint", route -> route.fulfill(
|
||||
* new Route.FulfillOptions().setPath(Paths.get("mock_data.json"))));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void fulfill(FulfillOptions options);
|
||||
/**
|
||||
* A request to be routed.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Request request();
|
||||
}
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Interface for capturing screencast frames from a page.
|
||||
*/
|
||||
public interface Screencast {
|
||||
class StartOptions {
|
||||
/**
|
||||
* Callback that receives JPEG-encoded frame data along with the page viewport size at the time of capture.
|
||||
*/
|
||||
public Consumer<ScreencastFrame> onFrame;
|
||||
/**
|
||||
* Path where the video should be saved when the screencast is stopped. When provided, video recording is started.
|
||||
*/
|
||||
public Path path;
|
||||
/**
|
||||
* The quality of the image, between 0-100.
|
||||
*/
|
||||
public Integer quality;
|
||||
|
||||
/**
|
||||
* Callback that receives JPEG-encoded frame data along with the page viewport size at the time of capture.
|
||||
*/
|
||||
public StartOptions setOnFrame(Consumer<ScreencastFrame> onFrame) {
|
||||
this.onFrame = onFrame;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Path where the video should be saved when the screencast is stopped. When provided, video recording is started.
|
||||
*/
|
||||
public StartOptions setPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* The quality of the image, between 0-100.
|
||||
*/
|
||||
public StartOptions setQuality(int quality) {
|
||||
this.quality = quality;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ShowOverlayOptions {
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Overlay stays until dismissed if not
|
||||
* provided.
|
||||
*/
|
||||
public Double duration;
|
||||
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Overlay stays until dismissed if not
|
||||
* provided.
|
||||
*/
|
||||
public ShowOverlayOptions setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ShowChapterOptions {
|
||||
/**
|
||||
* Optional description text displayed below the title.
|
||||
*/
|
||||
public String description;
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Defaults to {@code 2000}.
|
||||
*/
|
||||
public Double duration;
|
||||
|
||||
/**
|
||||
* Optional description text displayed below the title.
|
||||
*/
|
||||
public ShowChapterOptions setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Duration in milliseconds after which the overlay is automatically removed. Defaults to {@code 2000}.
|
||||
*/
|
||||
public ShowChapterOptions setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ShowActionsOptions {
|
||||
/**
|
||||
* How long each annotation is displayed in milliseconds. Defaults to {@code 500}.
|
||||
*/
|
||||
public Double duration;
|
||||
/**
|
||||
* Font size of the action title in pixels. Defaults to {@code 24}.
|
||||
*/
|
||||
public Integer fontSize;
|
||||
/**
|
||||
* Position of the action title overlay. Defaults to {@code "top-right"}.
|
||||
*/
|
||||
public AnnotatePosition position;
|
||||
|
||||
/**
|
||||
* How long each annotation is displayed in milliseconds. Defaults to {@code 500}.
|
||||
*/
|
||||
public ShowActionsOptions setDuration(double duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Font size of the action title in pixels. Defaults to {@code 24}.
|
||||
*/
|
||||
public ShowActionsOptions setFontSize(int fontSize) {
|
||||
this.fontSize = fontSize;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Position of the action title overlay. Defaults to {@code "top-right"}.
|
||||
*/
|
||||
public ShowActionsOptions setPosition(AnnotatePosition position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Starts the screencast. When {@code path} is provided, it saves video recording to the specified file. When {@code
|
||||
* onFrame} is provided, delivers JPEG-encoded frames to the callback. Both can be used together.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
default AutoCloseable start() {
|
||||
return start(null);
|
||||
}
|
||||
/**
|
||||
* Starts the screencast. When {@code path} is provided, it saves video recording to the specified file. When {@code
|
||||
* onFrame} is provided, delivers JPEG-encoded frames to the callback. Both can be used together.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
AutoCloseable start(StartOptions options);
|
||||
/**
|
||||
* Stops the screencast and video recording if active. If a video was being recorded, saves it to the path specified in
|
||||
* {@link com.microsoft.playwright.Screencast#start Screencast.start()}.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void stop();
|
||||
/**
|
||||
* Adds an overlay with the given HTML content. The overlay is displayed on top of the page until removed. Returns a
|
||||
* disposable that removes the overlay when disposed.
|
||||
*
|
||||
* @param html HTML content for the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
default AutoCloseable showOverlay(String html) {
|
||||
return showOverlay(html, null);
|
||||
}
|
||||
/**
|
||||
* Adds an overlay with the given HTML content. The overlay is displayed on top of the page until removed. Returns a
|
||||
* disposable that removes the overlay when disposed.
|
||||
*
|
||||
* @param html HTML content for the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
AutoCloseable showOverlay(String html, ShowOverlayOptions options);
|
||||
/**
|
||||
* Shows a chapter overlay with a title and optional description, centered on the page with a blurred backdrop. Useful for
|
||||
* narrating video recordings. The overlay is removed after the specified duration, or 2000ms.
|
||||
*
|
||||
* @param title Title text displayed prominently in the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
default void showChapter(String title) {
|
||||
showChapter(title, null);
|
||||
}
|
||||
/**
|
||||
* Shows a chapter overlay with a title and optional description, centered on the page with a blurred backdrop. Useful for
|
||||
* narrating video recordings. The overlay is removed after the specified duration, or 2000ms.
|
||||
*
|
||||
* @param title Title text displayed prominently in the overlay.
|
||||
* @since v1.59
|
||||
*/
|
||||
void showChapter(String title, ShowChapterOptions options);
|
||||
/**
|
||||
* Enables visual annotations on interacted elements. Returns a disposable that stops showing actions when disposed.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
default AutoCloseable showActions() {
|
||||
return showActions(null);
|
||||
}
|
||||
/**
|
||||
* Enables visual annotations on interacted elements. Returns a disposable that stops showing actions when disposed.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
AutoCloseable showActions(ShowActionsOptions options);
|
||||
/**
|
||||
* Shows overlays.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void showOverlays();
|
||||
/**
|
||||
* Removes action decorations.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void hideActions();
|
||||
/**
|
||||
* Hides overlays without removing them.
|
||||
*
|
||||
* @since v1.59
|
||||
*/
|
||||
void hideOverlays();
|
||||
}
|
||||
|
||||
@@ -17,193 +17,37 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Selectors can be used to install custom selector engines. See <a
|
||||
* href="https://playwright.dev/java/docs/extensibility">extensibility</a> for more information.
|
||||
* Selectors can be used to install custom selector engines. See
|
||||
* [Working with selectors](./selectors.md#working-with-selectors) for more information.
|
||||
*/
|
||||
public interface Selectors {
|
||||
class RegisterOptions {
|
||||
/**
|
||||
* Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but
|
||||
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is
|
||||
* not guaranteed when this engine is used together with other registered engines.
|
||||
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is not
|
||||
* guaranteed when this engine is used together with other registered engines.
|
||||
*/
|
||||
public Boolean contentScript;
|
||||
|
||||
/**
|
||||
* Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but
|
||||
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is
|
||||
* not guaranteed when this engine is used together with other registered engines.
|
||||
*/
|
||||
public RegisterOptions setContentScript(boolean contentScript) {
|
||||
public RegisterOptions withContentScript(boolean contentScript) {
|
||||
this.contentScript = contentScript;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* <pre>{@code
|
||||
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* String createTagNameEngine = "{\n" +
|
||||
* " // Returns the first element matching given selector in the root's subtree.\n" +
|
||||
* " query(root, selector) {\n" +
|
||||
* " return root.querySelector(selector);\n" +
|
||||
* " },\n" +
|
||||
* " // Returns all elements matching given selector in the root's subtree.\n" +
|
||||
* " queryAll(root, selector) {\n" +
|
||||
* " return Array.from(root.querySelectorAll(selector));\n" +
|
||||
* " }\n" +
|
||||
* "}";
|
||||
* // Register the engine. Selectors will be prefixed with "tag=".
|
||||
* playwright.selectors().register("tag", createTagNameEngine);
|
||||
* Browser browser = playwright.firefox().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void register(String name, String script) {
|
||||
register(name, script, null);
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* <pre>{@code
|
||||
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* String createTagNameEngine = "{\n" +
|
||||
* " // Returns the first element matching given selector in the root's subtree.\n" +
|
||||
* " query(root, selector) {\n" +
|
||||
* " return root.querySelector(selector);\n" +
|
||||
* " },\n" +
|
||||
* " // Returns all elements matching given selector in the root's subtree.\n" +
|
||||
* " queryAll(root, selector) {\n" +
|
||||
* " return Array.from(root.querySelectorAll(selector));\n" +
|
||||
* " }\n" +
|
||||
* "}";
|
||||
* // Register the engine. Selectors will be prefixed with "tag=".
|
||||
* playwright.selectors().register("tag", createTagNameEngine);
|
||||
* Browser browser = playwright.firefox().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void register(String name, String script) { register(name, script, null); }
|
||||
void register(String name, String script, RegisterOptions options);
|
||||
default void register(String name, Path path) { register(name, path, null); }
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
* An example of registering selector engine that queries elements based on a tag name:
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* <pre>{@code
|
||||
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* String createTagNameEngine = "{\n" +
|
||||
* " // Returns the first element matching given selector in the root's subtree.\n" +
|
||||
* " query(root, selector) {\n" +
|
||||
* " return root.querySelector(selector);\n" +
|
||||
* " },\n" +
|
||||
* " // Returns all elements matching given selector in the root's subtree.\n" +
|
||||
* " queryAll(root, selector) {\n" +
|
||||
* " return Array.from(root.querySelectorAll(selector));\n" +
|
||||
* " }\n" +
|
||||
* "}";
|
||||
* // Register the engine. Selectors will be prefixed with "tag=".
|
||||
* playwright.selectors().register("tag", createTagNameEngine);
|
||||
* Browser browser = playwright.firefox().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
|
||||
* contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance.
|
||||
*/
|
||||
default void register(String name, Path script) {
|
||||
register(name, script, null);
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* <pre>{@code
|
||||
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* String createTagNameEngine = "{\n" +
|
||||
* " // Returns the first element matching given selector in the root's subtree.\n" +
|
||||
* " query(root, selector) {\n" +
|
||||
* " return root.querySelector(selector);\n" +
|
||||
* " },\n" +
|
||||
* " // Returns all elements matching given selector in the root's subtree.\n" +
|
||||
* " queryAll(root, selector) {\n" +
|
||||
* " return Array.from(root.querySelectorAll(selector));\n" +
|
||||
* " }\n" +
|
||||
* "}";
|
||||
* // Register the engine. Selectors will be prefixed with "tag=".
|
||||
* playwright.selectors().register("tag", createTagNameEngine);
|
||||
* Browser browser = playwright.firefox().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
void register(String name, Path script, RegisterOptions options);
|
||||
/**
|
||||
* Defines custom attribute name to be used in {@link com.microsoft.playwright.Page#getByTestId Page.getByTestId()}. {@code
|
||||
* data-testid} is used by default.
|
||||
*
|
||||
* @param attributeName Test id attribute name.
|
||||
* @since v1.27
|
||||
*/
|
||||
void setTestIdAttribute(String attributeName);
|
||||
void register(String name, Path path, RegisterOptions options);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,14 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
/**
|
||||
* TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. {@link Page#waitForSelector
|
||||
* Page.waitForSelector()} or {@link BrowserType#launch BrowserType.launch()}.
|
||||
*/
|
||||
public class TimeoutError extends PlaywrightException {
|
||||
public TimeoutError(String message) {
|
||||
super(message);
|
||||
}
|
||||
import java.util.*;
|
||||
|
||||
public TimeoutError(String message, Throwable exception) {
|
||||
super(message, exception);
|
||||
}
|
||||
/**
|
||||
* - extends: [Error]
|
||||
*
|
||||
* <p> TimeoutError is emitted whenever certain operations are terminated due to timeout, e.g. [{@code method: Page.waitForSelector}]
|
||||
* or [{@code method: BrowserType.launch}].
|
||||
*/
|
||||
public interface TimeoutError {
|
||||
}
|
||||
|
||||
|
||||
@@ -16,24 +16,15 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on the
|
||||
* touchscreen can only be used in browser contexts that have been initialized with {@code hasTouch} set to true.
|
||||
*
|
||||
* <p> This class is limited to emulating tap gestures. For examples of other gestures simulated by manually dispatching touch
|
||||
* events, see the <a href="https://playwright.dev/java/docs/touch-events">emulating legacy touch events</a> page.
|
||||
* touchscreen can only be used in browser contexts that have been intialized with {@code hasTouch} set to true.
|
||||
*/
|
||||
public interface Touchscreen {
|
||||
/**
|
||||
* Dispatches a {@code touchstart} and {@code touchend} event with a single touch at the position ({@code x},{@code y}).
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link com.microsoft.playwright.Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser
|
||||
* context is false.
|
||||
*
|
||||
* @param x X coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @param y Y coordinate relative to the main frame's viewport in CSS pixels.
|
||||
* @since v1.8
|
||||
*/
|
||||
void tap(double x, double y);
|
||||
}
|
||||
|
||||
@@ -1,515 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
* .setSnapshots(true));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
* context.tracing().stop(new Tracing.StopOptions()
|
||||
* .setPath(Paths.get("trace.zip")));
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Tracing {
|
||||
class StartOptions {
|
||||
/**
|
||||
* When enabled, the trace is written to an unarchived file that is updated in real time as actions occur, instead of
|
||||
* caching changes and archiving them into a zip file at the end. This is useful for live trace viewing during test
|
||||
* execution.
|
||||
*/
|
||||
public Boolean live;
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* Tracing.stop()} instead.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview.
|
||||
*/
|
||||
public Boolean screenshots;
|
||||
/**
|
||||
* If this option is true tracing will
|
||||
* <ul>
|
||||
* <li> capture DOM snapshot on every action</li>
|
||||
* <li> record network activity</li>
|
||||
* </ul>
|
||||
*/
|
||||
public Boolean snapshots;
|
||||
/**
|
||||
* Whether to include source files for trace actions. List of the directories with source code for the application must be
|
||||
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by
|
||||
* ':' on other platforms).
|
||||
*/
|
||||
public Boolean sources;
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
public String title;
|
||||
|
||||
/**
|
||||
* When enabled, the trace is written to an unarchived file that is updated in real time as actions occur, instead of
|
||||
* caching changes and archiving them into a zip file at the end. This is useful for live trace viewing during test
|
||||
* execution.
|
||||
*/
|
||||
public StartOptions setLive(boolean live) {
|
||||
this.live = live;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stop
|
||||
* Tracing.stop()} instead.
|
||||
*/
|
||||
public StartOptions setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview.
|
||||
*/
|
||||
public StartOptions setScreenshots(boolean screenshots) {
|
||||
this.screenshots = screenshots;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If this option is true tracing will
|
||||
* <ul>
|
||||
* <li> capture DOM snapshot on every action</li>
|
||||
* <li> record network activity</li>
|
||||
* </ul>
|
||||
*/
|
||||
public StartOptions setSnapshots(boolean snapshots) {
|
||||
this.snapshots = snapshots;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to include source files for trace actions. List of the directories with source code for the application must be
|
||||
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by
|
||||
* ':' on other platforms).
|
||||
*/
|
||||
public StartOptions setSources(boolean sources) {
|
||||
this.sources = sources;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
public StartOptions setTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StartChunkOptions {
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
public String title;
|
||||
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} directory specified in {@link com.microsoft.playwright.BrowserType#launch BrowserType.launch()}. To specify
|
||||
* the final trace zip file name, you need to pass {@code path} option to {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public StartChunkOptions setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
public StartChunkOptions setTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StartHarOptions {
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
|
||||
* {@code attach} is specified, resources are persisted as separate files or entries in the ZIP archive. If {@code embed}
|
||||
* is specified, content is stored inline the HAR file as per HAR specification. Defaults to {@code attach} for {@code
|
||||
* .zip} output files and to {@code embed} for all other file extensions.
|
||||
*/
|
||||
public HarContentPolicy content;
|
||||
/**
|
||||
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
|
||||
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
|
||||
* full}.
|
||||
*/
|
||||
public HarMode mode;
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. Defaults to none.
|
||||
*/
|
||||
public Object urlFilter;
|
||||
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
|
||||
* {@code attach} is specified, resources are persisted as separate files or entries in the ZIP archive. If {@code embed}
|
||||
* is specified, content is stored inline the HAR file as per HAR specification. Defaults to {@code attach} for {@code
|
||||
* .zip} output files and to {@code embed} for all other file extensions.
|
||||
*/
|
||||
public StartHarOptions setContent(HarContentPolicy content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
|
||||
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
|
||||
* full}.
|
||||
*/
|
||||
public StartHarOptions setMode(HarMode mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. Defaults to none.
|
||||
*/
|
||||
public StartHarOptions setUrlFilter(String urlFilter) {
|
||||
this.urlFilter = urlFilter;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* A glob or regex pattern to filter requests that are stored in the HAR. Defaults to none.
|
||||
*/
|
||||
public StartHarOptions setUrlFilter(Pattern urlFilter) {
|
||||
this.urlFilter = urlFilter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GroupOptions {
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public Location location;
|
||||
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public GroupOptions setLocation(String file) {
|
||||
return setLocation(new Location(file));
|
||||
}
|
||||
/**
|
||||
* Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link
|
||||
* com.microsoft.playwright.Tracing#group Tracing.group()} call.
|
||||
*/
|
||||
public GroupOptions setLocation(Location location) {
|
||||
this.location = location;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StopOptions {
|
||||
/**
|
||||
* Export trace into the file with the given path.
|
||||
*/
|
||||
public Path path;
|
||||
|
||||
/**
|
||||
* Export trace into the file with the given path.
|
||||
*/
|
||||
public StopOptions setPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StopChunkOptions {
|
||||
/**
|
||||
* Export trace collected since the last {@link com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} call into
|
||||
* the file with the given path.
|
||||
*/
|
||||
public Path path;
|
||||
|
||||
/**
|
||||
* Export trace collected since the last {@link com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} call into
|
||||
* the file with the given path.
|
||||
*/
|
||||
public StopChunkOptions setPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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()
|
||||
* .setScreenshots(true)
|
||||
* .setSnapshots(true));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
* context.tracing().stop(new Tracing.StopOptions()
|
||||
* .setPath(Paths.get("trace.zip")));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.12
|
||||
*/
|
||||
default void start() {
|
||||
start(null);
|
||||
}
|
||||
/**
|
||||
* 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()
|
||||
* .setScreenshots(true)
|
||||
* .setSnapshots(true));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
* context.tracing().stop(new Tracing.StopOptions()
|
||||
* .setPath(Paths.get("trace.zip")));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.12
|
||||
*/
|
||||
void start(StartOptions options);
|
||||
/**
|
||||
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link
|
||||
* com.microsoft.playwright.Tracing#start Tracing.start()} once, and then create multiple trace chunks with {@link
|
||||
* com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} and {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
* .setSnapshots(true));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.getByText("Get Started").click();
|
||||
* // Everything between startChunk and stopChunk will be recorded in the trace.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace1.zip")));
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.navigate("http://example.com");
|
||||
* // Save a second trace file with different actions.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace2.zip")));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
default void startChunk() {
|
||||
startChunk(null);
|
||||
}
|
||||
/**
|
||||
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link
|
||||
* com.microsoft.playwright.Tracing#start Tracing.start()} once, and then create multiple trace chunks with {@link
|
||||
* com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} and {@link com.microsoft.playwright.Tracing#stopChunk
|
||||
* Tracing.stopChunk()}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
* .setSnapshots(true));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.getByText("Get Started").click();
|
||||
* // Everything between startChunk and stopChunk will be recorded in the trace.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace1.zip")));
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.navigate("http://example.com");
|
||||
* // Save a second trace file with different actions.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace2.zip")));
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
void startChunk(StartChunkOptions options);
|
||||
/**
|
||||
* Start recording a HAR (HTTP Archive) of network activity in this context. The HAR file is written to disk when {@link
|
||||
* com.microsoft.playwright.Tracing#stopHar Tracing.stopHar()} is called, or when the returned {@code Disposable} is
|
||||
* disposed.
|
||||
*
|
||||
* <p> Only one HAR recording can be active at a time per {@code BrowserContext}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().startHar(Paths.get("trace.har"));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
* context.tracing().stopHar();
|
||||
* }</pre>
|
||||
*
|
||||
* @param path Path on the filesystem to write the HAR file to. If the file name ends with {@code .zip}, the HAR is saved as a zip
|
||||
* archive with response bodies attached as separate files.
|
||||
* @since v1.60
|
||||
*/
|
||||
default AutoCloseable startHar(Path path) {
|
||||
return startHar(path, null);
|
||||
}
|
||||
/**
|
||||
* Start recording a HAR (HTTP Archive) of network activity in this context. The HAR file is written to disk when {@link
|
||||
* com.microsoft.playwright.Tracing#stopHar Tracing.stopHar()} is called, or when the returned {@code Disposable} is
|
||||
* disposed.
|
||||
*
|
||||
* <p> Only one HAR recording can be active at a time per {@code BrowserContext}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* context.tracing().startHar(Paths.get("trace.har"));
|
||||
* Page page = context.newPage();
|
||||
* page.navigate("https://playwright.dev");
|
||||
* context.tracing().stopHar();
|
||||
* }</pre>
|
||||
*
|
||||
* @param path Path on the filesystem to write the HAR file to. If the file name ends with {@code .zip}, the HAR is saved as a zip
|
||||
* archive with response bodies attached as separate files.
|
||||
* @since v1.60
|
||||
*/
|
||||
AutoCloseable startHar(Path path, StartHarOptions options);
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use {@code test.step} instead when available.
|
||||
*
|
||||
* <p> Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link
|
||||
* com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the
|
||||
* trace viewer.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // All actions between group and groupEnd
|
||||
* // will be shown in the trace viewer as a group.
|
||||
* page.context().tracing().group("Open Playwright.dev > API");
|
||||
* page.navigate("https://playwright.dev/");
|
||||
* page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
|
||||
* page.context().tracing().groupEnd();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Group name shown in the trace viewer.
|
||||
* @since v1.49
|
||||
*/
|
||||
default AutoCloseable group(String name) {
|
||||
return group(name, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use {@code test.step} instead when available.
|
||||
*
|
||||
* <p> Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link
|
||||
* com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the
|
||||
* trace viewer.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* // All actions between group and groupEnd
|
||||
* // will be shown in the trace viewer as a group.
|
||||
* page.context().tracing().group("Open Playwright.dev > API");
|
||||
* page.navigate("https://playwright.dev/");
|
||||
* page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
|
||||
* page.context().tracing().groupEnd();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Group name shown in the trace viewer.
|
||||
* @since v1.49
|
||||
*/
|
||||
AutoCloseable group(String name, GroupOptions options);
|
||||
/**
|
||||
* Closes the last group created by {@link com.microsoft.playwright.Tracing#group Tracing.group()}.
|
||||
*
|
||||
* @since v1.49
|
||||
*/
|
||||
void groupEnd();
|
||||
/**
|
||||
* Stop tracing.
|
||||
*
|
||||
* @since v1.12
|
||||
*/
|
||||
default void stop() {
|
||||
stop(null);
|
||||
}
|
||||
/**
|
||||
* Stop tracing.
|
||||
*
|
||||
* @since v1.12
|
||||
*/
|
||||
void stop(StopOptions options);
|
||||
/**
|
||||
* Stop the trace chunk. See {@link com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} for more details
|
||||
* about multiple trace chunks.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
default void stopChunk() {
|
||||
stopChunk(null);
|
||||
}
|
||||
/**
|
||||
* Stop the trace chunk. See {@link com.microsoft.playwright.Tracing#startChunk Tracing.startChunk()} for more details
|
||||
* about multiple trace chunks.
|
||||
*
|
||||
* @since v1.15
|
||||
*/
|
||||
void stopChunk(StopChunkOptions options);
|
||||
/**
|
||||
* Stop HAR recording and save the HAR file to the path given to {@link com.microsoft.playwright.Tracing#startHar
|
||||
* Tracing.startHar()}.
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
void stopHar();
|
||||
}
|
||||
|
||||
@@ -16,36 +16,17 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* When browser context is created with the {@code recordVideo} option, each page has a video object associated with it.
|
||||
* <pre>{@code
|
||||
* System.out.println(page.video().path());
|
||||
* }</pre>
|
||||
* When browser context is created with the {@code videosPath} option, each page has a video object associated with it.
|
||||
*/
|
||||
public interface Video {
|
||||
/**
|
||||
* Deletes the video file. Will wait for the video to finish if necessary.
|
||||
*
|
||||
* @since v1.11
|
||||
*/
|
||||
void delete();
|
||||
/**
|
||||
* Returns the file system path this video will be recorded to. The video is guaranteed to be written to the filesystem
|
||||
* upon closing the browser context. This method throws when connected remotely.
|
||||
*
|
||||
* @since v1.8
|
||||
* upon closing the browser context.
|
||||
*/
|
||||
Path path();
|
||||
/**
|
||||
* Saves the video to a user-specified path. It is safe to call this method while the video is still in progress, or after
|
||||
* the page has closed. This method waits until the page is closed and the video is fully saved.
|
||||
*
|
||||
* @param path Path where the video should be saved.
|
||||
* @since v1.11
|
||||
*/
|
||||
void saveAs(Path path);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.*;
|
||||
|
||||
/**
|
||||
* {@code WebError} class represents an unhandled exception thrown in the page. It is dispatched via the {@link
|
||||
* com.microsoft.playwright.BrowserContext#onWebError BrowserContext.onWebError()} event.
|
||||
* <pre>{@code
|
||||
* // Log all uncaught errors to the terminal
|
||||
* context.onWebError(webError -> {
|
||||
* System.out.println("Uncaught exception: " + webError.error());
|
||||
* });
|
||||
*
|
||||
* // Navigate to a page with an exception.
|
||||
* page.navigate("data:text/html,<script>throw new Error('Test')</script>");
|
||||
* }</pre>
|
||||
*/
|
||||
public interface WebError {
|
||||
/**
|
||||
* The page that produced this unhandled exception, if any.
|
||||
*
|
||||
* @since v1.38
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Unhandled error that was thrown.
|
||||
*
|
||||
* @since v1.38
|
||||
*/
|
||||
String error();
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
WebErrorLocation location();
|
||||
}
|
||||
|
||||
@@ -16,162 +16,70 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The {@code WebSocket} class represents WebSocket connections within a page. It provides the ability to inspect and
|
||||
* manipulate the data being transmitted and received.
|
||||
*
|
||||
* <p> If you want to intercept or modify WebSocket frames, consider using {@code WebSocketRoute}.
|
||||
* The {@code WebSocket} class represents websocket connections in the page.
|
||||
*/
|
||||
public interface WebSocket {
|
||||
interface FrameData {
|
||||
byte[] body();
|
||||
String text();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fired when the websocket closes.
|
||||
*/
|
||||
void onClose(Consumer<WebSocket> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onClose onClose(handler)}.
|
||||
*/
|
||||
void offClose(Consumer<WebSocket> handler);
|
||||
|
||||
/**
|
||||
* Fired when the websocket receives a frame.
|
||||
*/
|
||||
void onFrameReceived(Consumer<WebSocketFrame> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onFrameReceived onFrameReceived(handler)}.
|
||||
*/
|
||||
void offFrameReceived(Consumer<WebSocketFrame> handler);
|
||||
void onFrameReceived(Consumer<FrameData> handler);
|
||||
void offFrameReceived(Consumer<FrameData> handler);
|
||||
|
||||
/**
|
||||
* Fired when the websocket sends a frame.
|
||||
*/
|
||||
void onFrameSent(Consumer<WebSocketFrame> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onFrameSent onFrameSent(handler)}.
|
||||
*/
|
||||
void offFrameSent(Consumer<WebSocketFrame> handler);
|
||||
void onFrameSent(Consumer<FrameData> handler);
|
||||
void offFrameSent(Consumer<FrameData> handler);
|
||||
|
||||
/**
|
||||
* Fired when the websocket has an error.
|
||||
*/
|
||||
void onSocketError(Consumer<String> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onSocketError onSocketError(handler)}.
|
||||
*/
|
||||
void offSocketError(Consumer<String> handler);
|
||||
|
||||
|
||||
class WaitForFrameReceivedOptions {
|
||||
/**
|
||||
* Receives the {@code WebSocketFrame} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public Predicate<WebSocketFrame> predicate;
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Receives the {@code WebSocketFrame} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public WaitForFrameReceivedOptions setPredicate(Predicate<WebSocketFrame> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public WaitForFrameReceivedOptions setTimeout(double timeout) {
|
||||
public WaitForFrameReceivedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
FrameData waitForFrameReceived(Runnable code, WaitForFrameReceivedOptions options);
|
||||
default FrameData waitForFrameReceived(Runnable code) { return waitForFrameReceived(code, null); }
|
||||
|
||||
class WaitForFrameSentOptions {
|
||||
/**
|
||||
* Receives the {@code WebSocketFrame} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public Predicate<WebSocketFrame> predicate;
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Receives the {@code WebSocketFrame} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public WaitForFrameSentOptions setPredicate(Predicate<WebSocketFrame> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public WaitForFrameSentOptions setTimeout(double timeout) {
|
||||
public WaitForFrameSentOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
FrameData waitForFrameSent(Runnable code, WaitForFrameSentOptions options);
|
||||
default FrameData waitForFrameSent(Runnable code) { return waitForFrameSent(code, null); }
|
||||
|
||||
class WaitForSocketErrorOptions {
|
||||
public Double timeout;
|
||||
public WaitForSocketErrorOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
String waitForSocketError(Runnable code, WaitForSocketErrorOptions options);
|
||||
default String waitForSocketError(Runnable code) { return waitForSocketError(code, null); }
|
||||
|
||||
/**
|
||||
* Indicates that the web socket has been closed.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
boolean isClosed();
|
||||
/**
|
||||
* Contains the URL of the WebSocket.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
/**
|
||||
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
|
||||
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
|
||||
* error if the WebSocket or Page is closed before the frame is received.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
default WebSocketFrame waitForFrameReceived(Runnable callback) {
|
||||
return waitForFrameReceived(null, callback);
|
||||
}
|
||||
/**
|
||||
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
|
||||
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
|
||||
* error if the WebSocket or Page is closed before the frame is received.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
WebSocketFrame waitForFrameReceived(WaitForFrameReceivedOptions options, Runnable callback);
|
||||
/**
|
||||
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
|
||||
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
|
||||
* error if the WebSocket or Page is closed before the frame is sent.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
default WebSocketFrame waitForFrameSent(Runnable callback) {
|
||||
return waitForFrameSent(null, callback);
|
||||
}
|
||||
/**
|
||||
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
|
||||
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
|
||||
* error if the WebSocket or Page is closed before the frame is sent.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
WebSocketFrame waitForFrameSent(WaitForFrameSentOptions options, Runnable callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
|
||||
/**
|
||||
* The {@code WebSocketFrame} class represents frames sent over {@code WebSocket} connections in the page. Frame payload is
|
||||
* returned by either {@link com.microsoft.playwright.WebSocketFrame#text WebSocketFrame.text()} or {@link
|
||||
* com.microsoft.playwright.WebSocketFrame#binary WebSocketFrame.binary()} method depending on the its type.
|
||||
*/
|
||||
public interface WebSocketFrame {
|
||||
/**
|
||||
* Returns binary payload.
|
||||
*
|
||||
* @since v1.9
|
||||
*/
|
||||
byte[] binary();
|
||||
/**
|
||||
* Returns text payload.
|
||||
*
|
||||
* @since v1.9
|
||||
*/
|
||||
String text();
|
||||
}
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Whenever a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket">{@code WebSocket}</a> route is set up
|
||||
* with {@link com.microsoft.playwright.Page#routeWebSocket Page.routeWebSocket()} or {@link
|
||||
* com.microsoft.playwright.BrowserContext#routeWebSocket BrowserContext.routeWebSocket()}, the {@code WebSocketRoute}
|
||||
* object allows to handle the WebSocket, like an actual server would do.
|
||||
*
|
||||
* <p> <strong>Mocking</strong>
|
||||
*
|
||||
* <p> By default, the routed WebSocket will not connect to the server. This way, you can mock entire communication over the
|
||||
* WebSocket. Here is an example that responds to a {@code "request"} with a {@code "response"}.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("wss://example.com/ws", ws -> {
|
||||
* ws.onMessage(frame -> {
|
||||
* if ("request".equals(frame.text()))
|
||||
* ws.send("response");
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Since we do not call {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}
|
||||
* inside the WebSocket route handler, Playwright assumes that WebSocket will be mocked, and opens the WebSocket inside the
|
||||
* page automatically.
|
||||
*
|
||||
* <p> Here is another example that handles JSON messages:
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("wss://example.com/ws", ws -> {
|
||||
* ws.onMessage(frame -> {
|
||||
* JsonObject json = new JsonParser().parse(frame.text()).getAsJsonObject();
|
||||
* if ("question".equals(json.get("request").getAsString())) {
|
||||
* Map<String, String> result = new HashMap();
|
||||
* result.put("response", "answer");
|
||||
* ws.send(gson.toJson(result));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>Intercepting</strong>
|
||||
*
|
||||
* <p> Alternatively, you may want to connect to the actual server, but intercept messages in-between and modify or block them.
|
||||
* Calling {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()} returns a
|
||||
* server-side {@code WebSocketRoute} instance that you can send messages to, or handle incoming messages.
|
||||
*
|
||||
* <p> Below is an example that modifies some messages sent by the page to the server. Messages sent from the server to the
|
||||
* page are left intact, relying on the default forwarding.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("/ws", ws -> {
|
||||
* WebSocketRoute server = ws.connectToServer();
|
||||
* ws.onMessage(frame -> {
|
||||
* if ("request".equals(frame.text()))
|
||||
* server.send("request2");
|
||||
* else
|
||||
* server.send(frame.text());
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> After connecting to the server, all **messages are forwarded** between the page and the server by default.
|
||||
*
|
||||
* <p> However, if you call {@link com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} on the
|
||||
* original route, messages from the page to the server **will not be forwarded** anymore, but should instead be handled by
|
||||
* the {@code handler}.
|
||||
*
|
||||
* <p> Similarly, calling {@link com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} on the
|
||||
* server-side WebSocket will **stop forwarding messages** from the server to the page, and {@code handler} should take
|
||||
* care of them.
|
||||
*
|
||||
* <p> The following example blocks some messages in both directions. Since it calls {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} in both directions, there is no automatic
|
||||
* forwarding at all.
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("/ws", ws -> {
|
||||
* WebSocketRoute server = ws.connectToServer();
|
||||
* ws.onMessage(frame -> {
|
||||
* if (!"blocked-from-the-page".equals(frame.text()))
|
||||
* server.send(frame.text());
|
||||
* });
|
||||
* server.onMessage(frame -> {
|
||||
* if (!"blocked-from-the-server".equals(frame.text()))
|
||||
* ws.send(frame.text());
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
*/
|
||||
public interface WebSocketRoute {
|
||||
class CloseOptions {
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a>.
|
||||
*/
|
||||
public Integer code;
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
*/
|
||||
public String reason;
|
||||
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a>.
|
||||
*/
|
||||
public CloseOptions setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Optional <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
*/
|
||||
public CloseOptions setReason(String reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Closes one side of the WebSocket connection.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
default void close() {
|
||||
close(null);
|
||||
}
|
||||
/**
|
||||
* Closes one side of the WebSocket connection.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
void close(CloseOptions options);
|
||||
/**
|
||||
* By default, routed WebSocket does not connect to the server, so you can mock entire WebSocket communication. This method
|
||||
* connects to the actual WebSocket server, and returns the server-side {@code WebSocketRoute} instance, giving the ability
|
||||
* to send and receive messages from the server.
|
||||
*
|
||||
* <p> Once connected to the server:
|
||||
* <ul>
|
||||
* <li> Messages received from the server will be **automatically forwarded** to the WebSocket in the page, unless {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} is called on the server-side {@code
|
||||
* WebSocketRoute}.</li>
|
||||
* <li> Messages sent by the <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send">{@code
|
||||
* WebSocket.send()}</a> call in the page will be **automatically forwarded** to the server, unless {@link
|
||||
* com.microsoft.playwright.WebSocketRoute#onMessage WebSocketRoute.onMessage()} is called on the original {@code
|
||||
* WebSocketRoute}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> See examples at the top for more details.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
WebSocketRoute connectToServer();
|
||||
/**
|
||||
* Allows to handle <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close">{@code WebSocket.close}</a>.
|
||||
*
|
||||
* <p> By default, closing one side of the connection, either in the page or on the server, will close the other side. However,
|
||||
* when {@link com.microsoft.playwright.WebSocketRoute#onClose WebSocketRoute.onClose()} handler is set up, the default
|
||||
* forwarding of closure is disabled, and handler should take care of it.
|
||||
*
|
||||
* @param handler Function that will handle WebSocket closure. Received an optional <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#code">close code</a> and an optional <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close#reason">close reason</a>.
|
||||
* @since v1.48
|
||||
*/
|
||||
void onClose(BiConsumer<Integer, String> handler);
|
||||
/**
|
||||
* This method allows to handle messages that are sent by the WebSocket, either from the page or from the server.
|
||||
*
|
||||
* <p> When called on the original WebSocket route, this method handles messages sent from the page. You can handle this
|
||||
* messages by responding to them with {@link com.microsoft.playwright.WebSocketRoute#send WebSocketRoute.send()},
|
||||
* forwarding them to the server-side connection returned by {@link com.microsoft.playwright.WebSocketRoute#connectToServer
|
||||
* WebSocketRoute.connectToServer()} or do something else.
|
||||
*
|
||||
* <p> Once this method is called, messages are not automatically forwarded to the server or to the page - you should do that
|
||||
* manually by calling {@link com.microsoft.playwright.WebSocketRoute#send WebSocketRoute.send()}. See examples at the top
|
||||
* for more details.
|
||||
*
|
||||
* <p> Calling this method again will override the handler with a new one.
|
||||
*
|
||||
* @param handler Function that will handle messages.
|
||||
* @since v1.48
|
||||
*/
|
||||
void onMessage(Consumer<WebSocketFrame> handler);
|
||||
/**
|
||||
* Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called on
|
||||
* the result of {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}, sends
|
||||
* the message to the server. See examples at the top for more details.
|
||||
*
|
||||
* @param message Message to send.
|
||||
* @since v1.48
|
||||
*/
|
||||
void send(String message);
|
||||
/**
|
||||
* Sends a message to the WebSocket. When called on the original WebSocket, sends the message to the page. When called on
|
||||
* the result of {@link com.microsoft.playwright.WebSocketRoute#connectToServer WebSocketRoute.connectToServer()}, sends
|
||||
* the message to the server. See examples at the top for more details.
|
||||
*
|
||||
* @param message Message to send.
|
||||
* @since v1.48
|
||||
*/
|
||||
void send(byte[] message);
|
||||
/**
|
||||
* The list of WebSocket subprotocols requested by the page, as passed via the second argument to the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket">{@code WebSocket} constructor</a>.
|
||||
* Corresponds to the {@code Sec-WebSocket-Protocol} request header.
|
||||
*
|
||||
* <p> Returns an empty array if no protocols were specified.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.routeWebSocket("wss://example.com/ws", ws -> {
|
||||
* if (ws.protocols().contains("chat.v2")) {
|
||||
* ws.onMessage(frame -> ws.send("v2:" + frame.text()));
|
||||
* } else {
|
||||
* ws.close(1002, "Unsupported protocol");
|
||||
* }
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
List<String> protocols();
|
||||
/**
|
||||
* URL of the WebSocket created in the page.
|
||||
*
|
||||
* @since v1.48
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
@@ -16,203 +16,63 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The Worker class represents a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">WebWorker</a>.
|
||||
* {@code worker} event is emitted on the page object to signal a worker creation. {@code close} event is emitted on the
|
||||
* worker object when the worker is gone.
|
||||
* <pre>{@code
|
||||
* page.onWorker(worker -> {
|
||||
* System.out.println("Worker created: " + worker.url());
|
||||
* worker.onClose(worker1 -> System.out.println("Worker destroyed: " + worker1.url()));
|
||||
* });
|
||||
* System.out.println("Current workers:");
|
||||
* for (Worker worker : page.workers())
|
||||
* System.out.println(" " + worker.url());
|
||||
* }</pre>
|
||||
* The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). {@code worker}
|
||||
* event is emitted on the page object to signal a worker creation. {@code close} event is emitted on the worker object when the
|
||||
* worker is gone.
|
||||
*/
|
||||
public interface Worker {
|
||||
|
||||
/**
|
||||
* Emitted when this dedicated <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">WebWorker</a> is
|
||||
* terminated.
|
||||
*/
|
||||
void onClose(Consumer<Worker> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onClose onClose(handler)}.
|
||||
*/
|
||||
void offClose(Consumer<Worker> handler);
|
||||
|
||||
/**
|
||||
* Emitted when JavaScript within the worker calls one of console API methods, e.g. {@code console.log} or {@code
|
||||
* console.dir}.
|
||||
*/
|
||||
void onConsole(Consumer<ConsoleMessage> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onConsole onConsole(handler)}.
|
||||
*/
|
||||
void offConsole(Consumer<ConsoleMessage> handler);
|
||||
|
||||
class WaitForCloseOptions {
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public WaitForCloseOptions setTimeout(double timeout) {
|
||||
public WaitForCloseOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForConsoleMessageOptions {
|
||||
/**
|
||||
* Receives the {@code ConsoleMessage} object and resolves to true when the waiting should resolve.
|
||||
*/
|
||||
public Predicate<ConsoleMessage> predicate;
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public Double timeout;
|
||||
Worker waitForClose(Runnable code, WaitForCloseOptions options);
|
||||
default Worker waitForClose(Runnable code) { return waitForClose(code, null); }
|
||||
|
||||
/**
|
||||
* Receives the {@code ConsoleMessage} object and resolves to true when the waiting should resolve.
|
||||
*/
|
||||
public WaitForConsoleMessageOptions setPredicate(Predicate<ConsoleMessage> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
|
||||
* default value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*/
|
||||
public WaitForConsoleMessageOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
default Object evaluate(String pageFunction) {
|
||||
return evaluate(pageFunction, null);
|
||||
}
|
||||
/**
|
||||
* Returns the return value of {@code expression}.
|
||||
* Returns the return value of {@code pageFunction}
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
* com.microsoft.playwright.Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
|
||||
* <p> If the function passed to the {@code worker.evaluate} returns a [Promise], then {@code worker.evaluate} would wait for the promise
|
||||
* to resolve and return its value.
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns a
|
||||
* non-[Serializable] value, then {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns {@code
|
||||
* undefined}. Playwright also supports transferring some additional values that are not serializable by {@code JSON}:
|
||||
* {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
* <p> If the function passed to the {@code worker.evaluate} returns a non-[Serializable] value, then {@code worker.evaluate} returns
|
||||
* {@code undefined}. DevTools Protocol also supports transferring some additional values that are not serializable by {@code JSON}:
|
||||
* {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}, and bigint literals.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
* @param pageFunction Function to be evaluated in the worker context
|
||||
* @param arg Optional argument to pass to {@code pageFunction}
|
||||
*/
|
||||
default Object evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
Object evaluate(String pageFunction, Object arg);
|
||||
default JSHandle evaluateHandle(String pageFunction) {
|
||||
return evaluateHandle(pageFunction, null);
|
||||
}
|
||||
/**
|
||||
* Returns the return value of {@code expression}.
|
||||
* Returns the return value of {@code pageFunction} as in-page object (JSHandle).
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
* com.microsoft.playwright.Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
|
||||
* <p> The only difference between {@code worker.evaluate} and {@code worker.evaluateHandle} is that {@code worker.evaluateHandle} returns
|
||||
* in-page object (JSHandle).
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns a
|
||||
* non-[Serializable] value, then {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} returns {@code
|
||||
* undefined}. Playwright also supports transferring some additional values that are not serializable by {@code JSON}:
|
||||
* {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
* <p> If the function passed to the {@code worker.evaluateHandle} returns a [Promise], then {@code worker.evaluateHandle} would wait for
|
||||
* the promise to resolve and return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
*/
|
||||
Object evaluate(String expression, Object arg);
|
||||
/**
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
*
|
||||
* <p> The only difference between {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} and {@link
|
||||
* com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} is that {@link
|
||||
* com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} returns {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} returns a
|
||||
* <a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
|
||||
* {@link com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and
|
||||
* return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
*/
|
||||
default JSHandle evaluateHandle(String expression) {
|
||||
return evaluateHandle(expression, null);
|
||||
}
|
||||
/**
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
*
|
||||
* <p> The only difference between {@link com.microsoft.playwright.Worker#evaluate Worker.evaluate()} and {@link
|
||||
* com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} is that {@link
|
||||
* com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} returns {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function passed to the {@link com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} returns a
|
||||
* <a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
|
||||
* {@link com.microsoft.playwright.Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and
|
||||
* return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
*/
|
||||
JSHandle evaluateHandle(String expression, Object arg);
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @since v1.8
|
||||
* @param pageFunction Function to be evaluated in the page context
|
||||
* @param arg Optional argument to pass to {@code pageFunction}
|
||||
*/
|
||||
JSHandle evaluateHandle(String pageFunction, Object arg);
|
||||
String url();
|
||||
/**
|
||||
* Performs action and waits for the Worker to close.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
default Worker waitForClose(Runnable callback) {
|
||||
return waitForClose(null, callback);
|
||||
}
|
||||
/**
|
||||
* Performs action and waits for the Worker to close.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.10
|
||||
*/
|
||||
Worker waitForClose(WaitForCloseOptions options, Runnable callback);
|
||||
/**
|
||||
* Performs action and waits for a console message.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.57
|
||||
*/
|
||||
default ConsoleMessage waitForConsoleMessage(Runnable callback) {
|
||||
return waitForConsoleMessage(null, callback);
|
||||
}
|
||||
/**
|
||||
* Performs action and waits for a console message.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.57
|
||||
*/
|
||||
ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable callback);
|
||||
}
|
||||
|
||||
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
|
||||
/**
|
||||
* The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code
|
||||
* APIResponse} in the tests.
|
||||
* <pre>{@code
|
||||
* // ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestPage {
|
||||
* // ...
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* // ...
|
||||
* APIResponse response = page.request().get("https://playwright.dev");
|
||||
* assertThat(response).isOK();
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public interface APIResponseAssertions {
|
||||
/**
|
||||
* Makes the assertion check for the opposite condition.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> For example, this code tests that the response status is not successful:
|
||||
* <pre>{@code
|
||||
* assertThat(response).not().isOK();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.20
|
||||
*/
|
||||
APIResponseAssertions not();
|
||||
/**
|
||||
* Ensures the response status code is within {@code 200..299} range.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(response).isOK();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.18
|
||||
*/
|
||||
void isOK();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page}
|
||||
* state in the tests.
|
||||
* <pre>{@code
|
||||
* // ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestPage {
|
||||
* // ...
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* // ...
|
||||
* page.getByText("Sign in").click();
|
||||
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public interface PageAssertions {
|
||||
class MatchesAriaSnapshotOptions {
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public MatchesAriaSnapshotOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HasTitleOptions {
|
||||
/**
|
||||
* 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 HasTitleOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class HasURLOptions {
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression parameter if specified. A provided predicate ignores this flag.
|
||||
*/
|
||||
public Boolean ignoreCase;
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
|
||||
* expression parameter if specified. A provided predicate ignores this flag.
|
||||
*/
|
||||
public HasURLOptions setIgnoreCase(boolean ignoreCase) {
|
||||
this.ignoreCase = ignoreCase;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
*/
|
||||
public HasURLOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Makes the assertion check for the opposite condition.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
*
|
||||
* <p> For example, this code tests that the page URL doesn't contain {@code "error"}:
|
||||
* <pre>{@code
|
||||
* assertThat(page).not().hasURL("error");
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.20
|
||||
*/
|
||||
PageAssertions not();
|
||||
/**
|
||||
* Asserts that the page body matches the given <a href="https://playwright.dev/java/docs/aria-snapshots">accessibility
|
||||
* snapshot</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.navigate("https://demo.playwright.dev/todomvc/");
|
||||
* assertThat(page).matchesAriaSnapshot("""
|
||||
* - heading "todos"
|
||||
* - textbox "What needs to be done?"
|
||||
* """);
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
default void matchesAriaSnapshot(String expected) {
|
||||
matchesAriaSnapshot(expected, null);
|
||||
}
|
||||
/**
|
||||
* Asserts that the page body matches the given <a href="https://playwright.dev/java/docs/aria-snapshots">accessibility
|
||||
* snapshot</a>.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* page.navigate("https://demo.playwright.dev/todomvc/");
|
||||
* assertThat(page).matchesAriaSnapshot("""
|
||||
* - heading "todos"
|
||||
* - textbox "What needs to be done?"
|
||||
* """);
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.60
|
||||
*/
|
||||
void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions options);
|
||||
/**
|
||||
* Ensures the page has the given title.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
default void hasTitle(String titleOrRegExp) {
|
||||
hasTitle(titleOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page has the given title.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
void hasTitle(String titleOrRegExp, HasTitleOptions options);
|
||||
/**
|
||||
* Ensures the page has the given title.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
default void hasTitle(Pattern titleOrRegExp) {
|
||||
hasTitle(titleOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page has the given title.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasTitle("Playwright");
|
||||
* }</pre>
|
||||
*
|
||||
* @param titleOrRegExp Expected title or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
void hasTitle(Pattern titleOrRegExp, HasTitleOptions options);
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL(".com");
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected URL string or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
default void hasURL(String urlOrRegExp) {
|
||||
hasURL(urlOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL(".com");
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected URL string or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
void hasURL(String urlOrRegExp, HasURLOptions options);
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL(".com");
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected URL string or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
default void hasURL(Pattern urlOrRegExp) {
|
||||
hasURL(urlOrRegExp, null);
|
||||
}
|
||||
/**
|
||||
* Ensures the page is navigated to the given URL.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* assertThat(page).hasURL(".com");
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRegExp Expected URL string or RegExp.
|
||||
* @since v1.20
|
||||
*/
|
||||
void hasURL(Pattern urlOrRegExp, HasURLOptions options);
|
||||
}
|
||||
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.assertions;
|
||||
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.impl.APIResponseAssertionsImpl;
|
||||
import com.microsoft.playwright.impl.AssertionsTimeout;
|
||||
import com.microsoft.playwright.impl.LocatorAssertionsImpl;
|
||||
import com.microsoft.playwright.impl.PageAssertionsImpl;
|
||||
|
||||
/**
|
||||
* Playwright gives you Web-First Assertions with convenience methods for creating assertions that will wait and retry
|
||||
* until the expected condition is met.
|
||||
*
|
||||
* <p> Consider the following example:
|
||||
* <pre>{@code
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
*
|
||||
* public class TestExample {
|
||||
* // ...
|
||||
* @Test
|
||||
* void statusBecomesSubmitted() {
|
||||
* // ...
|
||||
* page.locator("#submit-button").click();
|
||||
* assertThat(page.locator(".status")).hasText("Submitted");
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Playwright will be re-testing the node with the selector {@code .status} until fetched Node has the {@code "Submitted"}
|
||||
* text. It will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is
|
||||
* reached. You can pass this timeout as an option.
|
||||
*
|
||||
* <p> By default, the timeout for assertions is set to 5 seconds.
|
||||
*/
|
||||
public interface PlaywrightAssertions {
|
||||
/**
|
||||
* Creates a {@code APIResponseAssertions} object for the given {@code APIResponse}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.assertThat(response).isOK();
|
||||
* }</pre>
|
||||
*
|
||||
* @param response {@code APIResponse} object to use for assertions.
|
||||
* @since v1.18
|
||||
*/
|
||||
static APIResponseAssertions assertThat(APIResponse response) {
|
||||
return new APIResponseAssertionsImpl(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code LocatorAssertions} object for the given {@code Locator}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.assertThat(locator).isVisible();
|
||||
* }</pre>
|
||||
*
|
||||
* @param locator {@code Locator} object to use for assertions.
|
||||
* @since v1.18
|
||||
*/
|
||||
static LocatorAssertions assertThat(Locator locator) {
|
||||
return new LocatorAssertionsImpl(locator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code PageAssertions} object for the given {@code Page}.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.assertThat(page).hasTitle("News");
|
||||
* }</pre>
|
||||
*
|
||||
* @param page {@code Page} object to use for assertions.
|
||||
* @since v1.18
|
||||
*/
|
||||
static PageAssertions assertThat(Page page) {
|
||||
return new PageAssertionsImpl(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes default timeout for Playwright assertions from 5 seconds to the specified value.
|
||||
*
|
||||
* <p> <strong>Usage</strong>
|
||||
* <pre>{@code
|
||||
* PlaywrightAssertions.setDefaultAssertionTimeout(30_000);
|
||||
* }</pre>
|
||||
*
|
||||
* @param timeout Timeout in milliseconds.
|
||||
* @since v1.25
|
||||
*/
|
||||
static void setDefaultAssertionTimeout(double timeout) {
|
||||
AssertionsTimeout.setDefaultTimeout(timeout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.microsoft.playwright.APIRequestContext;
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Request;
|
||||
import com.microsoft.playwright.options.FilePayload;
|
||||
import com.microsoft.playwright.options.RequestOptions;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
import static com.microsoft.playwright.impl.Utils.toFilePayload;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.microsoft.playwright.Tracing tracing() {
|
||||
return tracing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse delete(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "DELETE"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(DisposeOptions options) {
|
||||
if (options == null) {
|
||||
options = new DisposeOptions();
|
||||
}
|
||||
disposeReason = options.reason;
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("dispose", params, NO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse fetch(String urlOrRequest, RequestOptions options) {
|
||||
return fetchImpl(urlOrRequest, (RequestOptionsImpl) options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse fetch(Request request, RequestOptions optionsArg) {
|
||||
RequestOptionsImpl options = (RequestOptionsImpl) optionsArg;
|
||||
if (options == null) {
|
||||
options = new RequestOptionsImpl();
|
||||
}
|
||||
if (options.method == null) {
|
||||
options.method = request.method();
|
||||
}
|
||||
if (options.headers == null) {
|
||||
options.headers = request.headers();
|
||||
}
|
||||
if (options.data == null && options.form == null && options.multipart == null) {
|
||||
options.data = request.postDataBuffer();
|
||||
}
|
||||
return fetch(request.url(), options);
|
||||
}
|
||||
|
||||
private APIResponse fetchImpl(String url, RequestOptionsImpl options) {
|
||||
if (disposeReason != null) {
|
||||
throw new PlaywrightException(disposeReason);
|
||||
}
|
||||
if (options == null) {
|
||||
options = new RequestOptionsImpl();
|
||||
}
|
||||
options.timeout = timeoutSettings.timeout(options.timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("url", url);
|
||||
if (options.params != null) {
|
||||
Map<String, String> queryParams = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, ?> e : options.params.entrySet()) {
|
||||
queryParams.put(e.getKey(), "" + e.getValue());
|
||||
}
|
||||
params.add("params", toNameValueArray(queryParams.entrySet()));
|
||||
}
|
||||
if (options.method != null) {
|
||||
params.addProperty("method", options.method);
|
||||
}
|
||||
if (options.headers != null) {
|
||||
params.add("headers", toProtocol(options.headers));
|
||||
}
|
||||
|
||||
if (options.data != null) {
|
||||
byte[] bytes = null;
|
||||
if (options.data instanceof byte[]) {
|
||||
bytes = (byte[]) options.data;
|
||||
} else if (options.data instanceof String) {
|
||||
String stringData = (String) options.data;
|
||||
if (!isJsonContentType(options.headers) || isJsonParsable(stringData)) {
|
||||
bytes = (stringData).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
if (bytes == null) {
|
||||
params.addProperty("jsonData", jsonDataSerializer.toJson(options.data));
|
||||
} else {
|
||||
String base64 = Base64.getEncoder().encodeToString(bytes);
|
||||
params.addProperty("postData", base64);
|
||||
}
|
||||
}
|
||||
if (options.form != null) {
|
||||
params.add("formData", toNameValueArray(options.form.fields));
|
||||
}
|
||||
if (options.multipart != null) {
|
||||
params.add("multipartData", serializeMultipartData(options.multipart.fields));
|
||||
}
|
||||
if (options.failOnStatusCode != null) {
|
||||
params.addProperty("failOnStatusCode", options.failOnStatusCode);
|
||||
}
|
||||
if (options.ignoreHTTPSErrors != null) {
|
||||
params.addProperty("ignoreHTTPSErrors", options.ignoreHTTPSErrors);
|
||||
}
|
||||
if (options.maxRedirects != null) {
|
||||
if (options.maxRedirects < 0) {
|
||||
throw new PlaywrightException("'maxRedirects' should be greater than or equal to '0'");
|
||||
}
|
||||
params.addProperty("maxRedirects", options.maxRedirects);
|
||||
}
|
||||
if (options.maxRetries != null) {
|
||||
if (options.maxRetries < 0) {
|
||||
throw new PlaywrightException("'maxRetries' must be greater than or equal to '0'");
|
||||
}
|
||||
params.addProperty("maxRetries", options.maxRetries);
|
||||
}
|
||||
JsonObject json = sendMessage("fetch", params, timeoutSettings.timeout(options.timeout)).getAsJsonObject();
|
||||
return new APIResponseImpl(this, json.getAsJsonObject("response"));
|
||||
}
|
||||
|
||||
private static boolean isJsonContentType(Map<String, String> headers) {
|
||||
if (headers == null) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<String, String> e : headers.entrySet()) {
|
||||
if ("content-type".equalsIgnoreCase(e.getKey())) {
|
||||
return "application/json".equals(e.getValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static JsonArray serializeMultipartData(List<? extends Map.Entry<String, Object>> data) {
|
||||
JsonArray result = new JsonArray();
|
||||
for (Map.Entry<String, ?> e : data) {
|
||||
FilePayload filePayload = null;
|
||||
if (e.getValue() instanceof FilePayload) {
|
||||
filePayload = (FilePayload) e.getValue();
|
||||
} else if (e.getValue() instanceof Path) {
|
||||
filePayload = toFilePayload((Path) e.getValue());
|
||||
} else if (e.getValue() instanceof File) {
|
||||
filePayload = toFilePayload(((File) e.getValue()).toPath());
|
||||
}
|
||||
JsonObject item = new JsonObject();
|
||||
item.addProperty("name", e.getKey());
|
||||
if (filePayload == null) {
|
||||
item.addProperty("value", "" + e.getValue());
|
||||
} else {
|
||||
item.add("file", toProtocol(filePayload));
|
||||
}
|
||||
result.add(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse get(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "GET"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse head(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "HEAD"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse patch(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "PATCH"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse post(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "POST"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponse put(String url, RequestOptions options) {
|
||||
return fetch(url, ensureOptions(options, "PUT"));
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
private static RequestOptionsImpl ensureOptions(RequestOptions options, String method) {
|
||||
RequestOptionsImpl impl = Utils.clone((RequestOptionsImpl) options);
|
||||
if (impl == null) {
|
||||
impl = new RequestOptionsImpl();
|
||||
}
|
||||
if (impl.method == null) {
|
||||
impl.method = method;
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
private static boolean isJsonParsable(String value) {
|
||||
try {
|
||||
JsonElement result = JsonParser.parseString(value);
|
||||
if (result != null && result.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = result.getAsJsonPrimitive();
|
||||
if (primitive.isString() && value.equals(primitive.getAsString())) {
|
||||
// Gson parses unquoted strings too, but we don't want to treat them
|
||||
// as valid JSON.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (JsonSyntaxException error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.APIRequest;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.ClientCertificate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.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;
|
||||
|
||||
class APIRequestImpl implements APIRequest {
|
||||
private final PlaywrightImpl playwright;
|
||||
|
||||
APIRequestImpl(PlaywrightImpl playwright) {
|
||||
this.playwright = playwright;
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIRequestContextImpl newContext(NewContextOptions options) {
|
||||
if (options == null) {
|
||||
options = new NewContextOptions();
|
||||
} else {
|
||||
options = Utils.clone(options);
|
||||
}
|
||||
if (options.storageStatePath != null) {
|
||||
try {
|
||||
byte[] bytes = Files.readAllBytes(options.storageStatePath);
|
||||
options.storageState = new String(bytes, StandardCharsets.UTF_8);
|
||||
options.storageStatePath = null;
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read storage state from file", e);
|
||||
}
|
||||
}
|
||||
JsonObject storageState = null;
|
||||
if (options.storageState != null) {
|
||||
storageState = new Gson().fromJson(options.storageState, JsonObject.class);
|
||||
options.storageState = null;
|
||||
}
|
||||
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();
|
||||
APIRequestContextImpl context = playwright.connection.getExistingObject(result.getAsJsonObject("request").get("guid").getAsString());
|
||||
context.timeoutSettings.setDefaultTimeout(timeout);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.assertions.APIResponseAssertions;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class APIResponseAssertionsImpl implements APIResponseAssertions {
|
||||
private final APIResponse actual;
|
||||
private final boolean isNot;
|
||||
|
||||
APIResponseAssertionsImpl(APIResponse response, boolean isNot) {
|
||||
this.actual = response;
|
||||
this.isNot = isNot;
|
||||
}
|
||||
|
||||
public APIResponseAssertionsImpl(APIResponse response) {
|
||||
this(response, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIResponseAssertions not() {
|
||||
return new APIResponseAssertionsImpl(actual, !isNot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isOK() {
|
||||
if (actual.ok() == !isNot) {
|
||||
return;
|
||||
}
|
||||
String message = "Response status expected to be within [200..299] range, was " + actual.status();
|
||||
if (isNot) {
|
||||
message = message.replace("expected to", "expected not to");
|
||||
}
|
||||
List<String> logList = ((APIResponseImpl) actual).fetchLog();
|
||||
String log = String.join("\n", logList);
|
||||
if (!log.isEmpty()) {
|
||||
log = "\nCall log:\n" + log;
|
||||
}
|
||||
|
||||
String contentType = actual.headers().get("content-type");
|
||||
boolean isTextEncoding = contentType == null ? false : isTextualMimeType(contentType);
|
||||
String responseText = "";
|
||||
if (isTextEncoding) {
|
||||
String text = actual.text();
|
||||
if (text != null) {
|
||||
responseText = "\nResponse text:\n" + (text.length() > 1000 ? text.substring(0, 1000) : text);
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionFailedError(message + log + responseText);
|
||||
}
|
||||
static boolean isTextualMimeType(String mimeType) {
|
||||
return Pattern.matches("^(text/.*?|application/(json|(x-)?javascript|xml.*?|ecmascript|graphql|x-www-form-urlencoded)|image/svg(\\+xml)?|application/.*?(\\+json|\\+xml))(;\\s*charset=.*)?$", mimeType);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.HttpHeader;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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;
|
||||
|
||||
class APIResponseImpl implements APIResponse {
|
||||
final APIRequestContextImpl context;
|
||||
private final JsonObject initializer;
|
||||
private final RawHeaders headers;
|
||||
|
||||
APIResponseImpl(APIRequestContextImpl apiRequestContext, JsonObject response) {
|
||||
context = apiRequestContext;
|
||||
initializer = response;
|
||||
headers = new RawHeaders(asList(gson().fromJson(initializer.getAsJsonArray("headers"), HttpHeader[].class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] body() {
|
||||
try {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchResponseBody", params, NO_TIMEOUT).getAsJsonObject();
|
||||
if (!json.has("binary")) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
if (isSafeCloseError(e)) {
|
||||
throw new PlaywrightException("Response has been disposed");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
context.sendMessage("disposeAPIResponse", params, NO_TIMEOUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> headers() {
|
||||
return headers.headers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpHeader> headersArray() {
|
||||
return headers.headersArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ok() {
|
||||
int status = status();
|
||||
return status == 0 || (status >= 200 && status <= 299);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int status() {
|
||||
return initializer.get("status").getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String statusText() {
|
||||
return initializer.get("statusText").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String text() {
|
||||
return new String(body(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return initializer.get("url").getAsString();
|
||||
}
|
||||
|
||||
String fetchUid() {
|
||||
return initializer.get("fetchUid").getAsString();
|
||||
}
|
||||
|
||||
List<String> fetchLog() {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("fetchUid", fetchUid());
|
||||
JsonObject json = context.sendMessage("fetchLog", params, NO_TIMEOUT).getAsJsonObject();
|
||||
JsonArray log = json.get("log").getAsJsonArray();
|
||||
return gson().fromJson(log, new TypeToken<List<String>>() {}.getType());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Accessibility;
|
||||
import com.microsoft.playwright.AccessibilityNode;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class AccessibilityImpl implements Accessibility {
|
||||
private final PageImpl page;
|
||||
|
||||
AccessibilityImpl(PageImpl page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNode snapshot(SnapshotOptions options) {
|
||||
return page.withLogging("Accessibility.snapshot", () -> snapshotImpl(options));
|
||||
}
|
||||
|
||||
private AccessibilityNode snapshotImpl(SnapshotOptions options) {
|
||||
if (options == null) {
|
||||
options = new SnapshotOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
JsonObject json = page.sendMessage("accessibilitySnapshot", params).getAsJsonObject();
|
||||
if (!json.has("rootAXNode")) {
|
||||
return null;
|
||||
}
|
||||
return new AccessibilityNodeImpl(json.getAsJsonObject("rootAXNode"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.AccessibilityNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class AccessibilityNodeImpl implements AccessibilityNode {
|
||||
private final JsonObject json;
|
||||
|
||||
AccessibilityNodeImpl(JsonObject json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String role() {
|
||||
return json.get("role").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return json.get("name").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valueString() {
|
||||
if (!json.has("valueString")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("valueString").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double valueNumber() {
|
||||
if (!json.has("valueNumber")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("valueNumber").getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
if (!json.has("description")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("description").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String keyshortcuts() {
|
||||
if (!json.has("keyshortcuts")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("keyshortcuts").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String roledescription() {
|
||||
if (!json.has("roledescription")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("roledescription").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String valuetext() {
|
||||
if (!json.has("valuetext")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("valuetext").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean disabled() {
|
||||
if (!json.has("disabled")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("disabled").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean expanded() {
|
||||
if (!json.has("expanded")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("expanded").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean focused() {
|
||||
if (!json.has("focused")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("focused").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean modal() {
|
||||
if (!json.has("modal")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("modal").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean multiline() {
|
||||
if (!json.has("multiline")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("multiline").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean multiselectable() {
|
||||
if (!json.has("multiselectable")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("multiselectable").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean readonly() {
|
||||
if (!json.has("readonly")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("readonly").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean required() {
|
||||
if (!json.has("required")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("required").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean selected() {
|
||||
if (!json.has("selected")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("selected").getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CheckedState checked() {
|
||||
if (!json.has("checked")) {
|
||||
return null;
|
||||
}
|
||||
String value = json.get("checked").getAsString();
|
||||
switch (value) {
|
||||
case "checked": return CheckedState.CHECKED;
|
||||
case "unchecked": return CheckedState.UNCHECKED;
|
||||
case "mixed": return CheckedState.MIXED;
|
||||
default: throw new IllegalStateException("Unexpected value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PressedState pressed() {
|
||||
if (!json.has("pressed")) {
|
||||
return null;
|
||||
}
|
||||
String value = json.get("pressed").getAsString();
|
||||
switch (value) {
|
||||
case "pressed": return PressedState.PRESSED;
|
||||
case "released": return PressedState.RELEASED;
|
||||
case "mixed": return PressedState.MIXED;
|
||||
default: throw new IllegalStateException("Unexpected value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer level() {
|
||||
if (!json.has("level")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("level").getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double valuemin() {
|
||||
if (!json.has("valuemin")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("valuemin").getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double valuemax() {
|
||||
if (!json.has("valuemax")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("valuemax").getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String autocomplete() {
|
||||
if (!json.has("autocomplete")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("autocomplete").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String haspopup() {
|
||||
if (!json.has("haspopup")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("haspopup").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invalid() {
|
||||
if (!json.has("invalid")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("invalid").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String orientation() {
|
||||
if (!json.has("orientation")) {
|
||||
return null;
|
||||
}
|
||||
return json.get("orientation").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNode> children() {
|
||||
if (!json.has("children")) {
|
||||
return null;
|
||||
}
|
||||
List<AccessibilityNode> result = new ArrayList<>();
|
||||
for (JsonElement e : json.getAsJsonArray("children")) {
|
||||
result.add(new AccessibilityNodeImpl(e.getAsJsonObject()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.writeToFile;
|
||||
|
||||
class ArtifactImpl extends ChannelOwner {
|
||||
public ArtifactImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
public InputStream createReadStream() {
|
||||
JsonObject result = sendMessage("stream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(result.getAsJsonObject("stream").get("guid").getAsString());
|
||||
return stream.stream();
|
||||
}
|
||||
|
||||
byte[] readAllBytes() {
|
||||
final int bufLen = 1024 * 1024;
|
||||
byte[] buf = new byte[bufLen];
|
||||
int readLen;
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); InputStream stream = createReadStream()) {
|
||||
while ((readLen = stream.read(buf, 0, bufLen)) != -1) {
|
||||
outputStream.write(buf, 0, readLen);
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read artifact", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
sendMessage("cancel");
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
sendMessage("delete");
|
||||
}
|
||||
|
||||
public String failure() {
|
||||
JsonObject result = sendMessage("failure").getAsJsonObject();
|
||||
if (result.has("error")) {
|
||||
return result.get("error").getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Path pathAfterFinished() {
|
||||
if (connection.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use download.saveAs() to save a local copy.");
|
||||
}
|
||||
JsonObject json = sendMessage("pathAfterFinished").getAsJsonObject();
|
||||
return FileSystems.getDefault().getPath(json.get("value").getAsString());
|
||||
}
|
||||
|
||||
public void saveAs(Path path) {
|
||||
if (connection.isRemote) {
|
||||
JsonObject jsonObject = sendMessage("saveAsStream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(jsonObject.getAsJsonObject("stream").get("guid").getAsString());
|
||||
writeToFile(stream.stream(), path);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("path", path.toString());
|
||||
sendMessage("saveAs", params, NO_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
import org.opentest4j.ValueWrapper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
abstract class AssertionsBase {
|
||||
final boolean isNot;
|
||||
|
||||
AssertionsBase(boolean isNot) {
|
||||
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, List<ExpectedTextValue> expectedText, Object expected, String message, FrameExpectOptions options, String title) {
|
||||
if (options == null) {
|
||||
options = new FrameExpectOptions();
|
||||
}
|
||||
options.expectedText = expectedText;
|
||||
expectImpl(expression, options, expected, message, title);
|
||||
}
|
||||
|
||||
void expectImpl(String expression, FrameExpectOptions expectOptions, Object expected, String message, String title) {
|
||||
if (expectOptions.timeout == null) {
|
||||
expectOptions.timeout = AssertionsTimeout.defaultTimeout;
|
||||
}
|
||||
expectOptions.isNot = isNot;
|
||||
if (isNot) {
|
||||
message = message.replace("expected to", "expected not to");
|
||||
}
|
||||
FrameExpectResult result = doExpect(expression, expectOptions, title);
|
||||
if (result.matches == isNot) {
|
||||
Object actual;
|
||||
if (result.received == null) {
|
||||
actual = null;
|
||||
} else if (result.received.value != null) {
|
||||
actual = Serialization.deserialize(result.received.value);
|
||||
} else {
|
||||
actual = result.received.ariaSnapshot;
|
||||
}
|
||||
String log = (result.log == null) ? "" : String.join("\n", result.log);
|
||||
if (!log.isEmpty()) {
|
||||
log = "\nCall log:\n" + log;
|
||||
}
|
||||
if (result.errorMessage != null) {
|
||||
message += "\n" + result.errorMessage;
|
||||
}
|
||||
if (expected == null) {
|
||||
throw new AssertionFailedError(message + log);
|
||||
}
|
||||
ValueWrapper expectedValue = formatValue(expected);
|
||||
ValueWrapper actualValue = formatValue(actual);
|
||||
message += "\nExpected: " + expectedValue.getStringRepresentation() + "\nReceived: " + actualValue.getStringRepresentation() + "\n";
|
||||
throw new AssertionFailedError(message + log, expectedValue, actualValue);
|
||||
}
|
||||
}
|
||||
|
||||
abstract FrameExpectResult doExpect(String expression, FrameExpectOptions expectOptions, String title);
|
||||
|
||||
protected static ValueWrapper formatValue(Object value) {
|
||||
if (value == null || !value.getClass().isArray()) {
|
||||
return ValueWrapper.create(value);
|
||||
}
|
||||
Collection<String> values = asList((Object[]) value).stream().map(e -> e.toString()).collect(Collectors.toList());
|
||||
String stringRepresentation = "[" + String.join(", ", values) + "]";
|
||||
return ValueWrapper.create(value, stringRepresentation);
|
||||
}
|
||||
|
||||
static ExpectedTextValue expectedRegex(Pattern pattern) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.regexSource = pattern.pattern();
|
||||
if (pattern.flags() != 0) {
|
||||
expected.regexFlags = toJsRegexFlags(pattern);
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
|
||||
static Boolean shouldIgnoreCase(Object options) {
|
||||
if (options == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Field fromField = options.getClass().getDeclaredField("ignoreCase");
|
||||
Object value = fromField.get(options);
|
||||
return (Boolean) value;
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user