docs: document Android and friends (#5415)
These are experimental, currently available through `_android`.
This commit is contained in:
Родитель
44ff8b518b
Коммит
99f8e1cf63
|
@ -0,0 +1,81 @@
|
|||
# class: Android
|
||||
* langs: js
|
||||
|
||||
Playwright has **experimental** support for Android automation. You can access android namespace via:
|
||||
|
||||
```js
|
||||
const { _android } = require('playwright');
|
||||
```
|
||||
|
||||
An example of the Android automation script would be:
|
||||
|
||||
```js
|
||||
const { _android } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
// Connect to the device.
|
||||
const [device] = await playwright._android.devices();
|
||||
console.log(`Model: ${device.model()}`);
|
||||
console.log(`Serial: ${device.serial()}`);
|
||||
// Take screenshot of the whole device.
|
||||
await device.screenshot({ path: 'device.png' });
|
||||
|
||||
{
|
||||
// --------------------- WebView -----------------------
|
||||
|
||||
// Launch an application with WebView.
|
||||
await device.shell('am force-stop org.chromium.webview_shell');
|
||||
await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
|
||||
// Get the WebView.
|
||||
const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
|
||||
|
||||
// Fill the input box.
|
||||
await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
|
||||
await device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter');
|
||||
|
||||
// Work with WebView's page as usual.
|
||||
const page = await webview.page();
|
||||
await page.page.waitForNavigation({ url: /.*microsoft\/playwright.*/ });
|
||||
console.log(await page.title());
|
||||
}
|
||||
|
||||
{
|
||||
// --------------------- Browser -----------------------
|
||||
|
||||
// Launch Chrome browser.
|
||||
await device.shell('am force-stop com.android.chrome');
|
||||
const context = await device.launchBrowser();
|
||||
|
||||
// Use BrowserContext as usual.
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://webkit.org/');
|
||||
console.log(await page.evaluate(() => window.location.href));
|
||||
await page.screenshot({ path: 'page.png' });
|
||||
|
||||
await context.close();
|
||||
}
|
||||
|
||||
// Close the device.
|
||||
await device.close();
|
||||
})();
|
||||
```
|
||||
|
||||
Note that since you don't need Playwright to install web browsers when testing Android, you can omit browser download via setting the following environment variable when installing Playwright:
|
||||
|
||||
```sh js
|
||||
$ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
|
||||
```
|
||||
|
||||
## async method: Android.devices
|
||||
- returns: <[Array]<[AndroidDevice]>>
|
||||
|
||||
Returns the list of detected Android devices.
|
||||
|
||||
## method: Android.setDefaultTimeout
|
||||
|
||||
This setting will change the default maximum time for all the methods accepting [`param: timeout`] option.
|
||||
|
||||
### param: Android.setDefaultTimeout.timeout
|
||||
- `timeout` <[float]>
|
||||
|
||||
Maximum time in milliseconds
|
|
@ -0,0 +1,368 @@
|
|||
# class: AndroidDevice
|
||||
* langs: js
|
||||
|
||||
[AndroidDevice] represents a connected device, either real hardware or emulated. Devices can be obtained using [`method: Android.devices`].
|
||||
|
||||
## event: AndroidDevice.webView
|
||||
- type: <[AndroidWebView]>
|
||||
|
||||
Emitted when a new WebView instance is detected.
|
||||
|
||||
## async method: AndroidDevice.close
|
||||
|
||||
Disconnects from the device.
|
||||
|
||||
## async method: AndroidDevice.drag
|
||||
|
||||
Drags the widget defined by [`param: selector`] towards [`param: dest`] point.
|
||||
|
||||
### param: AndroidDevice.drag.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to drag.
|
||||
|
||||
### param: AndroidDevice.drag.dest
|
||||
- `dest` <[Object]>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
Point to drag to.
|
||||
|
||||
### option: AndroidDevice.drag.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the drag in pixels per second.
|
||||
|
||||
### option: AndroidDevice.drag.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.fill
|
||||
|
||||
Fills the specific [`param: selector`] input box with [`param: text`].
|
||||
|
||||
### param: AndroidDevice.fill.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to fill.
|
||||
|
||||
### param: AndroidDevice.fill.text
|
||||
- `text` <[string]>
|
||||
|
||||
Text to be filled in the input box.
|
||||
|
||||
### option: AndroidDevice.fill.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.fling
|
||||
|
||||
Flings the widget defined by [`param: selector`] in the specified [`param: direction`].
|
||||
|
||||
### param: AndroidDevice.fling.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to fling.
|
||||
|
||||
### param: AndroidDevice.fling.direction
|
||||
- `direction` <[AndroidFlingDirection]<"down"|"up"|"left"|"right">>
|
||||
|
||||
Fling direction.
|
||||
|
||||
### option: AndroidDevice.fling.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the fling in pixels per second.
|
||||
|
||||
### option: AndroidDevice.fling.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.info
|
||||
- returns: <[AndroidElementInfo]>
|
||||
|
||||
Returns information about a widget defined by [`param: selector`].
|
||||
|
||||
### param: AndroidDevice.info.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to return information about.
|
||||
|
||||
## property: AndroidDevice.input
|
||||
- type: <[AndroidInput]>
|
||||
|
||||
## async method: AndroidDevice.installApk
|
||||
|
||||
Installs an apk on the device.
|
||||
|
||||
### param: AndroidDevice.installApk.file
|
||||
- `file` <[string]|[Buffer]>
|
||||
|
||||
Either a path to the apk file, or apk file content.
|
||||
|
||||
### option: AndroidDevice.installApk.args
|
||||
- `args` <[Array]<[string]>>
|
||||
|
||||
Optional arguments to pass to the `shell:cmd package install` call. Defaults to `-r -t -S`.
|
||||
|
||||
## async method: AndroidDevice.launchBrowser
|
||||
- returns: <[ChromiumBrowserContext]>
|
||||
|
||||
Launches Chrome browser on the device, and returns its persistent context.
|
||||
|
||||
### option: AndroidDevice.launchBrowser.pkg
|
||||
- `command` <[string]>
|
||||
|
||||
Optional package name to launch instead of default Chrome for Android.
|
||||
|
||||
### option: AndroidDevice.launchBrowser.-inline- = %%-shared-context-params-list-%%
|
||||
|
||||
## async method: AndroidDevice.longTap
|
||||
|
||||
Performs a long tap on the widget defined by [`param: selector`].
|
||||
|
||||
### param: AndroidDevice.longTap.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to tap on.
|
||||
|
||||
### option: AndroidDevice.longTap.timeout = %%-android-timeout-%%
|
||||
|
||||
## method: AndroidDevice.model
|
||||
- returns: <[string]>
|
||||
|
||||
Device model.
|
||||
|
||||
## async method: AndroidDevice.open
|
||||
- returns: <[AndroidSocket]>
|
||||
|
||||
Launches a process in the shell on the device and returns a socket to communicate with the launched process.
|
||||
|
||||
### param: AndroidDevice.open.command
|
||||
- `command` <[string]> Shell command to execute.
|
||||
|
||||
|
||||
## async method: AndroidDevice.pinchClose
|
||||
|
||||
Pinches the widget defined by [`param: selector`] in the closing direction.
|
||||
|
||||
### param: AndroidDevice.pinchClose.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to pinch close.
|
||||
|
||||
### param: AndroidDevice.pinchClose.percent
|
||||
- `percent` <[float]>
|
||||
|
||||
The size of the pinch as a percentage of the widget's size.
|
||||
|
||||
### option: AndroidDevice.pinchClose.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the pinch in pixels per second.
|
||||
|
||||
### option: AndroidDevice.pinchClose.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.pinchOpen
|
||||
|
||||
Pinches the widget defined by [`param: selector`] in the open direction.
|
||||
|
||||
### param: AndroidDevice.pinchOpen.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to pinch open.
|
||||
|
||||
### param: AndroidDevice.pinchOpen.percent
|
||||
- `percent` <[float]>
|
||||
|
||||
The size of the pinch as a percentage of the widget's size.
|
||||
|
||||
### option: AndroidDevice.pinchOpen.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the pinch in pixels per second.
|
||||
|
||||
### option: AndroidDevice.pinchOpen.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.press
|
||||
|
||||
Presses the specific [`param: key`] in the widget defined by [`param: selector`].
|
||||
|
||||
### param: AndroidDevice.press.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to press the key in.
|
||||
|
||||
### param: AndroidDevice.press.key
|
||||
- `key` <[AndroidKey]>
|
||||
|
||||
The key to press.
|
||||
|
||||
### option: AndroidDevice.press.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.push
|
||||
|
||||
Copies a file to the device.
|
||||
|
||||
### param: AndroidDevice.push.file
|
||||
- `file` <[string]|[Buffer]>
|
||||
|
||||
Either a path to the file, or file content.
|
||||
|
||||
### param: AndroidDevice.push.path
|
||||
- `path` <[string]>
|
||||
|
||||
Path to the file on the device.
|
||||
|
||||
### option: AndroidDevice.push.mode
|
||||
- `mode` <[int]>
|
||||
|
||||
Optional file mode, defaults to `644` (`rw-r--r--`).
|
||||
|
||||
## async method: AndroidDevice.screenshot
|
||||
- returns: <[Buffer]>
|
||||
|
||||
Returns the buffer with the captured screenshot of the device.
|
||||
|
||||
### option: AndroidDevice.screenshot.path
|
||||
- `path` <[path]>
|
||||
|
||||
The file path to save the image to. If [`option: path`] is a
|
||||
relative path, then it is resolved relative to the current working directory. If no path is provided, the image won't be
|
||||
saved to the disk.
|
||||
|
||||
## async method: AndroidDevice.scroll
|
||||
|
||||
Scrolls the widget defined by [`param: selector`] in the specified [`param: direction`].
|
||||
|
||||
### param: AndroidDevice.scroll.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to scroll.
|
||||
|
||||
### param: AndroidDevice.scroll.direction
|
||||
- `direction` <[AndroidScrollDirection]<"down"|"up"|"left"|"right">>
|
||||
|
||||
Scroll direction.
|
||||
|
||||
### param: AndroidDevice.scroll.percent
|
||||
- `percent` <[float]>
|
||||
|
||||
Distance to scroll as a percentage of the widget's size.
|
||||
|
||||
### option: AndroidDevice.scroll.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the scroll in pixels per second.
|
||||
|
||||
### option: AndroidDevice.scroll.timeout = %%-android-timeout-%%
|
||||
|
||||
## method: AndroidDevice.serial
|
||||
- returns: <[string]>
|
||||
|
||||
Device serial number.
|
||||
|
||||
## method: AndroidDevice.setDefaultTimeout
|
||||
|
||||
This setting will change the default maximum time for all the methods accepting [`param: timeout`] option.
|
||||
|
||||
### param: AndroidDevice.setDefaultTimeout.timeout
|
||||
- `timeout` <[float]>
|
||||
|
||||
Maximum time in milliseconds
|
||||
|
||||
## async method: AndroidDevice.shell
|
||||
- returns: <[Buffer]>
|
||||
|
||||
Executes a shell command on the device and returns its output.
|
||||
|
||||
### param: AndroidDevice.shell.command
|
||||
- `command` <[string]>
|
||||
|
||||
Shell command to execute.
|
||||
|
||||
|
||||
## async method: AndroidDevice.swipe
|
||||
|
||||
Swipes the widget defined by [`param: selector`] in the specified [`param: direction`].
|
||||
|
||||
### param: AndroidDevice.swipe.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to swipe.
|
||||
|
||||
### param: AndroidDevice.swipe.direction
|
||||
- `direction` <[AndroidSwipeDirection]<"down"|"up"|"left"|"right">>
|
||||
|
||||
Swipe direction.
|
||||
|
||||
### param: AndroidDevice.swipe.percent
|
||||
- `percent` <[float]>
|
||||
|
||||
Distance to swipe as a percentage of the widget's size.
|
||||
|
||||
### option: AndroidDevice.swipe.speed
|
||||
- `speed` <[float]>
|
||||
|
||||
Optional speed of the swipe in pixels per second.
|
||||
|
||||
### option: AndroidDevice.swipe.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.tap
|
||||
|
||||
Taps on the widget defined by [`param: selector`].
|
||||
|
||||
### param: AndroidDevice.tap.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to tap on.
|
||||
|
||||
### option: AndroidDevice.tap.duration
|
||||
- `duration` <[float]>
|
||||
|
||||
Optional duration of the tap in milliseconds.
|
||||
|
||||
### option: AndroidDevice.tap.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.wait
|
||||
|
||||
Waits for the specific [`param: selector`] to either appear or disappear, depending on the [`option: state`].
|
||||
|
||||
### param: AndroidDevice.wait.selector
|
||||
- `selector` <[AndroidSelector]>
|
||||
|
||||
Selector to wait for.
|
||||
|
||||
### option: AndroidDevice.wait.state
|
||||
- `state` <"gone">
|
||||
|
||||
Optional state. Can be either:
|
||||
* default - wait for element to be present.
|
||||
* `'gone'` - wait for element to not be present.
|
||||
|
||||
### option: AndroidDevice.wait.timeout = %%-android-timeout-%%
|
||||
|
||||
## async method: AndroidDevice.waitForEvent
|
||||
- returns: <[any]>
|
||||
|
||||
Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy value.
|
||||
|
||||
### param: AndroidDevice.waitForEvent.event = %%-wait-for-event-event-%%
|
||||
|
||||
### param: AndroidDevice.waitForEvent.optionsOrPredicate
|
||||
- `optionsOrPredicate` <[function]|[Object]>
|
||||
- `predicate` <[function]> receives the event data and resolves to truthy value when the waiting should resolve.
|
||||
- `timeout` <[float]> maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to
|
||||
disable timeout. The default value can be changed by using the [`method: AndroidDevice.setDefaultTimeout`].
|
||||
|
||||
Either a predicate that receives an event or an options object. Optional.
|
||||
|
||||
## async method: AndroidDevice.webView
|
||||
- returns: <[AndroidWebView]>
|
||||
|
||||
This method waits until [AndroidWebView] matching the [`option: selector`] is opened and returns it. If there is already an open [AndroidWebView] matching the [`option: selector`], returns immediately.
|
||||
|
||||
### param: AndroidDevice.webView.selector
|
||||
- `selector` <[Object]>
|
||||
- `pkg` <[string]> Package identifier.
|
||||
|
||||
### option: AndroidDevice.webView.timeout = %%-android-timeout-%%
|
||||
|
||||
## method: AndroidDevice.webViews
|
||||
- returns: <[Array]<[AndroidWebView]>>
|
||||
|
||||
Currently open WebViews.
|
|
@ -0,0 +1,78 @@
|
|||
# class: AndroidInput
|
||||
* langs: js
|
||||
|
||||
## async method: AndroidInput.drag
|
||||
|
||||
Performs a drag between [`param: from`] and [`param: to`] points.
|
||||
|
||||
### param: AndroidInput.drag.from
|
||||
- `from` <[Object]>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
The start point of the drag.
|
||||
|
||||
### param: AndroidInput.drag.to
|
||||
- `to` <[Object]>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
The end point of the drag.
|
||||
|
||||
### param: AndroidInput.drag.steps
|
||||
- `steps` <[int]>
|
||||
|
||||
The number of steps in the drag. Each step takes 5 milliseconds to complete.
|
||||
|
||||
## async method: AndroidInput.press
|
||||
|
||||
Presses the [`param: key`].
|
||||
|
||||
### param: AndroidInput.press.key
|
||||
- `key` <[AndroidKey]>
|
||||
|
||||
Key to press.
|
||||
|
||||
|
||||
## async method: AndroidInput.swipe
|
||||
|
||||
Swipes following the path defined by [`param: segments`].
|
||||
|
||||
### param: AndroidInput.swipe.from
|
||||
- `from` <[Object]>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
The point to start swiping from.
|
||||
|
||||
### param: AndroidInput.swipe.segments
|
||||
- `segments` <[Array]<[Object]>>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
Points following the [`param: from`] point in the swipe gesture.
|
||||
|
||||
### param: AndroidInput.swipe.steps
|
||||
- `steps` <[int]>
|
||||
|
||||
The number of steps for each segment. Each step takes 5 milliseconds to complete, so 100 steps means half a second per each segment.
|
||||
|
||||
## async method: AndroidInput.tap
|
||||
|
||||
Taps at the specified [`param: point`].
|
||||
|
||||
### param: AndroidInput.tap.point
|
||||
- `point` <[Object]>
|
||||
- `x` <[float]>
|
||||
- `y` <[float]>
|
||||
|
||||
The point to tap at.
|
||||
|
||||
## async method: AndroidInput.type
|
||||
|
||||
Types [`param: text`] into currently focused widget.
|
||||
|
||||
### param: AndroidInput.type.text
|
||||
- `text` <[string]>
|
||||
|
||||
Text to type.
|
|
@ -0,0 +1,26 @@
|
|||
# class: AndroidSocket
|
||||
* langs: js
|
||||
|
||||
[AndroidSocket] is a way to communicate with a process launched on the [AndroidDevice]. Use [`method: AndroidDevice.open`] to open a socket.
|
||||
|
||||
## event: AndroidSocket.close
|
||||
|
||||
Emitted when the socket is closed.
|
||||
|
||||
## event: AndroidSocket.data
|
||||
- type: <[Buffer]>
|
||||
|
||||
Emitted when data is available to read from the socket.
|
||||
|
||||
## async method: AndroidSocket.close
|
||||
|
||||
Closes the socket.
|
||||
|
||||
## async method: AndroidSocket.write
|
||||
|
||||
Writes some [`param: data`] to the socket.
|
||||
|
||||
### param: AndroidSocket.write.data
|
||||
- `data` <[Buffer]>
|
||||
|
||||
Data to write.
|
|
@ -0,0 +1,23 @@
|
|||
# class: AndroidWebView
|
||||
* langs: js
|
||||
|
||||
[AndroidWebView] represents a WebView open on the [AndroidDevice]. WebView is usually obtained using [`method: AndroidDevice.webView`].
|
||||
|
||||
## event: AndroidWebView.close
|
||||
|
||||
Emitted when the WebView is closed.
|
||||
|
||||
## async method: AndroidWebView.page
|
||||
- returns: <[Page]>
|
||||
|
||||
Connects to the WebView and returns a regular Playwright [Page] to interact with.
|
||||
|
||||
## method: AndroidWebView.pid
|
||||
- returns: <[int]>
|
||||
|
||||
WebView process PID.
|
||||
|
||||
## method: AndroidWebView.pkg
|
||||
- returns: <[string]>
|
||||
|
||||
WebView package identifier.
|
|
@ -498,6 +498,13 @@ Receives the event data and resolves to truthy value when the waiting should res
|
|||
Maximum time to wait for in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
|
||||
The default value can be changed by using the [`method: BrowserContext.setDefaultTimeout`].
|
||||
|
||||
## android-timeout
|
||||
* langs: js
|
||||
- `timeout` <[float]>
|
||||
|
||||
Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
using the [`method: AndroidDevice.setDefaultTimeout`] method.
|
||||
|
||||
## shared-context-params-list
|
||||
- %%-context-option-acceptdownloads-%%
|
||||
- %%-context-option-ignorehttpserrors-%%
|
||||
|
|
|
@ -8,38 +8,71 @@ title: "Mobile (experimental)"
|
|||
Mobile support is experimental and uses prefixed provisional API.
|
||||
:::
|
||||
|
||||
You can try Playwright against Chrome for Android today. This support is experimental. Support for devices is tracked in the issue [#1122](https://github.com/microsoft/playwright/issues/1122).
|
||||
You can try Playwright against Android, Chrome for Android and Android WebView today. This support is experimental. Support for devices is tracked in the issue [#1122](https://github.com/microsoft/playwright/issues/1122).
|
||||
|
||||
See [Android] for documentation.
|
||||
|
||||
## Requirements
|
||||
|
||||
- [ADB daemon](https://developer.android.com/studio/command-line/adb) running and authenticated with your device.
|
||||
- Android device or AVD Emulator.
|
||||
- [ADB daemon](https://developer.android.com/studio/command-line/adb) running and authenticated with your device. Typically running `adb devices` is all you need to do.
|
||||
- [`Chrome 87`](https://play.google.com/store/apps/details?id=com.android.chrome) or newer installed on the device
|
||||
- "Enable command line on non-rooted devices" enabled in `chrome://flags`.
|
||||
|
||||
> Playwright will be looking for ADB daemon on the default port `5037`. It will use the first device available. Typically running `adb devices` is all you need to do.
|
||||
|
||||
## How to run
|
||||
|
||||
```js
|
||||
const { _clank } = require('playwright');
|
||||
const { _android } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const context = await _clank.launchPersistentContext('', {
|
||||
viewport: null
|
||||
});
|
||||
const [page] = context.pages();
|
||||
await page.goto('https://webkit.org/');
|
||||
console.log(await page.evaluate(() => window.location.href));
|
||||
await page.screenshot({ path: 'example.png' });
|
||||
await context.close();
|
||||
// Connect to the device.
|
||||
const [device] = await playwright._android.devices();
|
||||
console.log(`Model: ${device.model()}`);
|
||||
console.log(`Serial: ${device.serial()}`);
|
||||
// Take screenshot of the whole device.
|
||||
await device.screenshot({ path: 'device.png' });
|
||||
|
||||
{
|
||||
// --------------------- WebView -----------------------
|
||||
|
||||
// Launch an application with WebView.
|
||||
await device.shell('am force-stop org.chromium.webview_shell');
|
||||
await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
|
||||
// Get the WebView.
|
||||
const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
|
||||
|
||||
// Fill the input box.
|
||||
await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
|
||||
await device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter');
|
||||
|
||||
// Work with WebView's page as usual.
|
||||
const page = await webview.page();
|
||||
await page.page.waitForNavigation({ url: /.*microsoft\/playwright.*/ });
|
||||
console.log(await page.title());
|
||||
}
|
||||
|
||||
{
|
||||
// --------------------- Browser -----------------------
|
||||
|
||||
// Launch Chrome browser.
|
||||
await device.shell('am force-stop com.android.chrome');
|
||||
const context = await device.launchBrowser();
|
||||
|
||||
// Use BrowserContext as usual.
|
||||
const page = await context.newPage();
|
||||
await page.goto('https://webkit.org/');
|
||||
console.log(await page.evaluate(() => window.location.href));
|
||||
await page.screenshot({ path: 'page.png' });
|
||||
|
||||
await context.close();
|
||||
}
|
||||
|
||||
// Close the device.
|
||||
await device.close();
|
||||
})();
|
||||
```
|
||||
|
||||
> [Clank](https://chromium.googlesource.com/chromium/src/+/master/docs/memory/android_dev_tips.md) is a code name for Chrome for Android.
|
||||
|
||||
## Known limitations
|
||||
- Raw USB operation is not yet supported, so you need ADB.
|
||||
- Only `launchPersistentContext` works, launching ephemeral contexts is not supported.
|
||||
- Passing `viewport: null` is necessary to make sure resolution is not emulated.
|
||||
- Device needs to be awake to produce screenshots. Enabling "Stay awake" developer mode will help.
|
||||
- We didn't run all the tests against the device, so not everything works.
|
||||
|
|
|
@ -21,3 +21,4 @@ export const webkit: types.BrowserType<types.WebKitBrowser>;
|
|||
export const chromium: types.BrowserType<types.ChromiumBrowser>;
|
||||
export const firefox: types.BrowserType<types.FirefoxBrowser>;
|
||||
export const _electron: types.Electron;
|
||||
export const _android: types.Android;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Android } from './types/android';
|
||||
import { Android } from './types/types';
|
||||
export * from './types/types';
|
||||
export * from './types/android';
|
||||
export const android: Android;
|
||||
|
|
|
@ -21,7 +21,7 @@ import * as channels from '../protocol/channels';
|
|||
import { Events } from './events';
|
||||
import { BrowserContext, prepareBrowserContextOptions } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import * as androidApi from '../../types/android';
|
||||
import * as api from '../../types/types';
|
||||
import * as types from './types';
|
||||
import { Page } from './page';
|
||||
import { TimeoutSettings } from '../utils/timeoutSettings';
|
||||
|
@ -29,10 +29,10 @@ import { Waiter } from './waiter';
|
|||
import { EventEmitter } from 'events';
|
||||
import { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||
|
||||
type Direction = 'down' | 'up' | 'left' | 'right';
|
||||
type Direction = 'down' | 'up' | 'left' | 'right';
|
||||
type SpeedOptions = { speed?: number };
|
||||
|
||||
export class Android extends ChannelOwner<channels.AndroidChannel, channels.AndroidInitializer> implements androidApi.Android {
|
||||
export class Android extends ChannelOwner<channels.AndroidChannel, channels.AndroidInitializer> implements api.Android {
|
||||
readonly _timeoutSettings: TimeoutSettings;
|
||||
|
||||
static from(android: channels.AndroidChannel): Android {
|
||||
|
@ -57,7 +57,7 @@ export class Android extends ChannelOwner<channels.AndroidChannel, channels.Andr
|
|||
}
|
||||
}
|
||||
|
||||
export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, channels.AndroidDeviceInitializer> implements androidApi.AndroidDevice {
|
||||
export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, channels.AndroidDeviceInitializer> implements api.AndroidDevice {
|
||||
readonly _timeoutSettings: TimeoutSettings;
|
||||
private _webViews = new Map<number, AndroidWebView>();
|
||||
|
||||
|
@ -65,11 +65,11 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
|
|||
return (androidDevice as any)._object;
|
||||
}
|
||||
|
||||
input: Input;
|
||||
input: AndroidInput;
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.AndroidDeviceInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this.input = new Input(this);
|
||||
this.input = new AndroidInput(this);
|
||||
this._timeoutSettings = new TimeoutSettings((parent as Android)._timeoutSettings);
|
||||
this._channel.on('webViewAdded', ({ webView }) => this._onWebViewAdded(webView));
|
||||
this._channel.on('webViewRemoved', ({ pid }) => this._onWebViewRemoved(pid));
|
||||
|
@ -115,83 +115,77 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
|
|||
});
|
||||
}
|
||||
|
||||
async wait(selector: androidApi.AndroidSelector, options?: { state?: 'gone' } & types.TimeoutOptions) {
|
||||
async wait(selector: api.AndroidSelector, options?: { state?: 'gone' } & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.wait', async () => {
|
||||
await this._channel.wait({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async fill(selector: androidApi.AndroidSelector, text: string, options?: types.TimeoutOptions) {
|
||||
async fill(selector: api.AndroidSelector, text: string, options?: types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.fill', async () => {
|
||||
await this._channel.fill({ selector: toSelectorChannel(selector), text, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async press(selector: androidApi.AndroidSelector, key: androidApi.AndroidKey, options?: types.TimeoutOptions) {
|
||||
async press(selector: api.AndroidSelector, key: api.AndroidKey, options?: types.TimeoutOptions) {
|
||||
await this.tap(selector, options);
|
||||
await this.input.press(key);
|
||||
}
|
||||
|
||||
async tap(selector: androidApi.AndroidSelector, options?: { duration?: number } & types.TimeoutOptions) {
|
||||
async tap(selector: api.AndroidSelector, options?: { duration?: number } & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.tap', async () => {
|
||||
await this._channel.tap({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async drag(selector: androidApi.AndroidSelector, dest: types.Point, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async drag(selector: api.AndroidSelector, dest: types.Point, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.drag', async () => {
|
||||
await this._channel.drag({ selector: toSelectorChannel(selector), dest, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async fling(selector: androidApi.AndroidSelector, direction: Direction, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async fling(selector: api.AndroidSelector, direction: Direction, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.fling', async () => {
|
||||
await this._channel.fling({ selector: toSelectorChannel(selector), direction, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async longTap(selector: androidApi.AndroidSelector, options?: types.TimeoutOptions) {
|
||||
async longTap(selector: api.AndroidSelector, options?: types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.longTap', async () => {
|
||||
await this._channel.longTap({ selector: toSelectorChannel(selector), ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async pinchClose(selector: androidApi.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async pinchClose(selector: api.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.pinchClose', async () => {
|
||||
await this._channel.pinchClose({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async pinchOpen(selector: androidApi.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async pinchOpen(selector: api.AndroidSelector, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.pinchOpen', async () => {
|
||||
await this._channel.pinchOpen({ selector: toSelectorChannel(selector), percent, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async scroll(selector: androidApi.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async scroll(selector: api.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.scroll', async () => {
|
||||
await this._channel.scroll({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async swipe(selector: androidApi.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
async swipe(selector: api.AndroidSelector, direction: Direction, percent: number, options?: SpeedOptions & types.TimeoutOptions) {
|
||||
await this._wrapApiCall('androidDevice.swipe', async () => {
|
||||
await this._channel.swipe({ selector: toSelectorChannel(selector), direction, percent, ...options });
|
||||
});
|
||||
}
|
||||
|
||||
async info(selector: androidApi.AndroidSelector): Promise<androidApi.AndroidElementInfo> {
|
||||
async info(selector: api.AndroidSelector): Promise<api.AndroidElementInfo> {
|
||||
return await this._wrapApiCall('androidDevice.info', async () => {
|
||||
return (await this._channel.info({ selector: toSelectorChannel(selector) })).info;
|
||||
});
|
||||
}
|
||||
|
||||
async tree(): Promise<androidApi.AndroidElementInfo> {
|
||||
return await this._wrapApiCall('androidDevice.tree', async () => {
|
||||
return (await this._channel.tree()).tree;
|
||||
});
|
||||
}
|
||||
|
||||
async screenshot(options: { path?: string } = {}): Promise<Buffer> {
|
||||
return await this._wrapApiCall('androidDevice.screenshot', async () => {
|
||||
const { binary } = await this._channel.screenshot();
|
||||
|
@ -255,7 +249,7 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel, c
|
|||
}
|
||||
}
|
||||
|
||||
export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel, channels.AndroidSocketInitializer> implements androidApi.AndroidSocket {
|
||||
export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel, channels.AndroidSocketInitializer> implements api.AndroidSocket {
|
||||
static from(androidDevice: channels.AndroidSocketChannel): AndroidSocket {
|
||||
return (androidDevice as any)._object;
|
||||
}
|
||||
|
@ -285,7 +279,7 @@ async function loadFile(file: string | Buffer): Promise<string> {
|
|||
return file.toString('base64');
|
||||
}
|
||||
|
||||
class Input implements androidApi.AndroidInput {
|
||||
export class AndroidInput implements api.AndroidInput {
|
||||
private _device: AndroidDevice;
|
||||
|
||||
constructor(device: AndroidDevice) {
|
||||
|
@ -298,7 +292,7 @@ class Input implements androidApi.AndroidInput {
|
|||
});
|
||||
}
|
||||
|
||||
async press(key: androidApi.AndroidKey) {
|
||||
async press(key: api.AndroidKey) {
|
||||
return this._device._wrapApiCall('androidDevice.inputPress', async () => {
|
||||
await this._device._channel.inputPress({ key });
|
||||
});
|
||||
|
@ -323,7 +317,7 @@ class Input implements androidApi.AndroidInput {
|
|||
}
|
||||
}
|
||||
|
||||
function toSelectorChannel(selector: androidApi.AndroidSelector): channels.AndroidSelector {
|
||||
function toSelectorChannel(selector: api.AndroidSelector): channels.AndroidSelector {
|
||||
const {
|
||||
checkable,
|
||||
checked,
|
||||
|
@ -373,7 +367,7 @@ function toSelectorChannel(selector: androidApi.AndroidSelector): channels.Andro
|
|||
};
|
||||
}
|
||||
|
||||
export class AndroidWebView extends EventEmitter implements androidApi.AndroidWebView {
|
||||
export class AndroidWebView extends EventEmitter implements api.AndroidWebView {
|
||||
private _device: AndroidDevice;
|
||||
private _data: channels.AndroidWebView;
|
||||
private _pagePromise: Promise<Page> | undefined;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
export { Accessibility } from './accessibility';
|
||||
export { Android, AndroidDevice, AndroidWebView, AndroidInput, AndroidSocket } from './android';
|
||||
export { Browser } from './browser';
|
||||
export { BrowserContext } from './browserContext';
|
||||
export { BrowserServer } from './browserType';
|
||||
|
|
|
@ -100,10 +100,6 @@ export class AndroidDeviceDispatcher extends Dispatcher<AndroidDevice, channels.
|
|||
return { info: await this._object.send('info', params) };
|
||||
}
|
||||
|
||||
async tree(params: channels.AndroidDeviceTreeParams): Promise<channels.AndroidDeviceTreeResult> {
|
||||
return { tree: await this._object.send('tree', params) };
|
||||
}
|
||||
|
||||
async inputType(params: channels.AndroidDeviceInputTypeParams) {
|
||||
const text = params.text;
|
||||
const keyCodes: number[] = [];
|
||||
|
|
|
@ -2604,7 +2604,6 @@ export interface AndroidDeviceChannel extends Channel {
|
|||
scroll(params: AndroidDeviceScrollParams, metadata?: Metadata): Promise<AndroidDeviceScrollResult>;
|
||||
swipe(params: AndroidDeviceSwipeParams, metadata?: Metadata): Promise<AndroidDeviceSwipeResult>;
|
||||
info(params: AndroidDeviceInfoParams, metadata?: Metadata): Promise<AndroidDeviceInfoResult>;
|
||||
tree(params?: AndroidDeviceTreeParams, metadata?: Metadata): Promise<AndroidDeviceTreeResult>;
|
||||
screenshot(params?: AndroidDeviceScreenshotParams, metadata?: Metadata): Promise<AndroidDeviceScreenshotResult>;
|
||||
inputType(params: AndroidDeviceInputTypeParams, metadata?: Metadata): Promise<AndroidDeviceInputTypeResult>;
|
||||
inputPress(params: AndroidDeviceInputPressParams, metadata?: Metadata): Promise<AndroidDeviceInputPressResult>;
|
||||
|
@ -2740,11 +2739,6 @@ export type AndroidDeviceInfoOptions = {
|
|||
export type AndroidDeviceInfoResult = {
|
||||
info: AndroidElementInfo,
|
||||
};
|
||||
export type AndroidDeviceTreeParams = {};
|
||||
export type AndroidDeviceTreeOptions = {};
|
||||
export type AndroidDeviceTreeResult = {
|
||||
tree: AndroidElementInfo,
|
||||
};
|
||||
export type AndroidDeviceScreenshotParams = {};
|
||||
export type AndroidDeviceScreenshotOptions = {};
|
||||
export type AndroidDeviceScreenshotResult = {
|
||||
|
|
|
@ -2291,10 +2291,6 @@ AndroidDevice:
|
|||
returns:
|
||||
info: AndroidElementInfo
|
||||
|
||||
tree:
|
||||
returns:
|
||||
tree: AndroidElementInfo
|
||||
|
||||
screenshot:
|
||||
returns:
|
||||
binary: binary
|
||||
|
|
|
@ -1010,7 +1010,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||
scheme.AndroidDeviceInfoParams = tObject({
|
||||
selector: tType('AndroidSelector'),
|
||||
});
|
||||
scheme.AndroidDeviceTreeParams = tOptional(tObject({}));
|
||||
scheme.AndroidDeviceScreenshotParams = tOptional(tObject({}));
|
||||
scheme.AndroidDeviceInputTypeParams = tObject({
|
||||
text: tString,
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Android, AndroidDevice } from '../../types/android';
|
||||
import type { Android, AndroidDevice } from '../..';
|
||||
import { folio as baseFolio } from '../fixtures';
|
||||
|
||||
const fixtures = baseFolio.extend<{
|
||||
|
|
|
@ -19,7 +19,7 @@ const {installCoverageHooks} = require('./coverage');
|
|||
|
||||
const browserName = process.env.BROWSER || 'chromium';
|
||||
|
||||
const api = new Set(installCoverageHooks(browserName).coverage.keys());
|
||||
let api = new Set(installCoverageHooks(browserName).coverage.keys());
|
||||
|
||||
// coverage exceptions
|
||||
|
||||
|
@ -38,8 +38,8 @@ if (browserName !== 'chromium') {
|
|||
if (browserName === 'webkit')
|
||||
api.delete('browserContext.clearPermissions');
|
||||
|
||||
// Screencast APIs that are not publicly available.
|
||||
api.delete('browserContext.emit("screencaststarted")');
|
||||
// Android coverage is abysmal.
|
||||
api = new Set(Array.from(api).filter(name => !name.toLowerCase().startsWith('android')));
|
||||
|
||||
const coverageDir = path.join(__dirname, 'coverage-report');
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ function traceAPICoverage(apiCoverage, api, events) {
|
|||
const method = Reflect.get(classType.prototype, methodName);
|
||||
if (methodName === 'constructor' || typeof methodName !== 'string' || methodName.startsWith('_') || typeof method !== 'function')
|
||||
continue;
|
||||
|
||||
|
||||
apiCoverage.set(`${className}.${methodName}`, false);
|
||||
const override = function(...args) {
|
||||
apiCoverage.set(`${className}.${methodName}`, true);
|
||||
|
|
|
@ -27,7 +27,6 @@ import { installCoverageHooks } from './coverage';
|
|||
import { folio as httpFolio } from './http.fixtures';
|
||||
import { folio as playwrightFolio } from './playwright.fixtures';
|
||||
import { PlaywrightClient } from '../lib/remote/playwrightClient';
|
||||
import type { Android } from '../types/android';
|
||||
export { expect, config } from 'folio';
|
||||
|
||||
const removeFolderAsync = util.promisify(require('rimraf'));
|
||||
|
@ -190,8 +189,3 @@ export const beforeEach = folio.beforeEach;
|
|||
export const afterEach = folio.afterEach;
|
||||
export const beforeAll = folio.beforeAll;
|
||||
export const afterAll = folio.afterAll;
|
||||
|
||||
|
||||
declare module '../index' {
|
||||
const _android: Android;
|
||||
}
|
||||
|
|
|
@ -1,161 +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.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import { BrowserContextOptions, Page, ChromiumBrowserContext } from './types';
|
||||
|
||||
export interface Android extends EventEmitter {
|
||||
setDefaultTimeout(timeout: number): void;
|
||||
devices(): Promise<AndroidDevice[]>;
|
||||
}
|
||||
|
||||
export interface AndroidDevice extends EventEmitter {
|
||||
input: AndroidInput;
|
||||
|
||||
setDefaultTimeout(timeout: number): void;
|
||||
on(event: 'webview', handler: (webView: AndroidWebView) => void): this;
|
||||
waitForEvent(event: string, optionsOrPredicate?: (data: any) => boolean | { timeout?: number, predicate?: (data: any) => boolean }): Promise<any>;
|
||||
|
||||
serial(): string;
|
||||
model(): string;
|
||||
webViews(): AndroidWebView[];
|
||||
webView(selector: { pkg: string }, options?: { timeout?: number }): Promise<AndroidWebView>;
|
||||
shell(command: string): Promise<Buffer>;
|
||||
open(command: string): Promise<AndroidSocket>;
|
||||
installApk(file: string | Buffer, options?: { args?: string[] }): Promise<void>;
|
||||
push(file: string | Buffer, path: string, options?: { mode?: number }): Promise<void>;
|
||||
launchBrowser(options?: BrowserContextOptions & { pkg?: string }): Promise<ChromiumBrowserContext>;
|
||||
close(): Promise<void>;
|
||||
|
||||
wait(selector: AndroidSelector, options?: { state?: 'gone' } & { timeout?: number }): Promise<void>;
|
||||
fill(selector: AndroidSelector, text: string, options?: { timeout?: number }): Promise<void>;
|
||||
press(selector: AndroidSelector, key: AndroidKey, options?: { duration?: number } & { timeout?: number }): Promise<void>;
|
||||
tap(selector: AndroidSelector, options?: { duration?: number } & { timeout?: number }): Promise<void>;
|
||||
drag(selector: AndroidSelector, dest: { x: number, y: number }, options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
fling(selector: AndroidSelector, direction: 'down' | 'up' | 'left' | 'right', options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
longTap(selector: AndroidSelector, options?: { timeout?: number }): Promise<void>;
|
||||
pinchClose(selector: AndroidSelector, percent: number, options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
pinchOpen(selector: AndroidSelector, percent: number, options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
scroll(selector: AndroidSelector, direction: 'down' | 'up' | 'left' | 'right', percent: number, options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
swipe(selector: AndroidSelector, direction: 'down' | 'up' | 'left' | 'right', percent: number, options?: { speed?: number } & { timeout?: number }): Promise<void>;
|
||||
|
||||
info(selector: AndroidSelector): Promise<AndroidElementInfo>;
|
||||
screenshot(options?: { path?: string }): Promise<Buffer>;
|
||||
}
|
||||
|
||||
export interface AndroidSocket extends EventEmitter {
|
||||
on(event: 'data', handler: (data: Buffer) => void): this;
|
||||
on(event: 'close', handler: () => void): this;
|
||||
write(data: Buffer): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface AndroidInput {
|
||||
type(text: string): Promise<void>;
|
||||
press(key: AndroidKey): Promise<void>;
|
||||
tap(point: { x: number, y: number }): Promise<void>;
|
||||
swipe(from: { x: number, y: number }, segments: { x: number, y: number }[], steps: number): Promise<void>;
|
||||
drag(from: { x: number, y: number }, to: { x: number, y: number }, steps: number): Promise<void>;
|
||||
}
|
||||
|
||||
export interface AndroidWebView extends EventEmitter {
|
||||
on(event: 'close', handler: () => void): this;
|
||||
pid(): number;
|
||||
pkg(): string;
|
||||
page(): Promise<Page>;
|
||||
}
|
||||
|
||||
export type AndroidElementInfo = {
|
||||
clazz: string;
|
||||
desc: string;
|
||||
res: string;
|
||||
pkg: string;
|
||||
text: string;
|
||||
bounds: { x: number, y: number, width: number, height: number };
|
||||
checkable: boolean;
|
||||
checked: boolean;
|
||||
clickable: boolean;
|
||||
enabled: boolean;
|
||||
focusable: boolean;
|
||||
focused: boolean;
|
||||
longClickable: boolean;
|
||||
scrollable: boolean;
|
||||
selected: boolean;
|
||||
};
|
||||
|
||||
export type AndroidSelector = {
|
||||
checkable?: boolean,
|
||||
checked?: boolean,
|
||||
clazz?: string | RegExp,
|
||||
clickable?: boolean,
|
||||
depth?: number,
|
||||
desc?: string | RegExp,
|
||||
enabled?: boolean,
|
||||
focusable?: boolean,
|
||||
focused?: boolean,
|
||||
hasChild?: { selector: AndroidSelector },
|
||||
hasDescendant?: { selector: AndroidSelector, maxDepth?: number },
|
||||
longClickable?: boolean,
|
||||
pkg?: string | RegExp,
|
||||
res?: string | RegExp,
|
||||
scrollable?: boolean,
|
||||
selected?: boolean,
|
||||
text?: string | RegExp,
|
||||
};
|
||||
|
||||
export type AndroidKey =
|
||||
'Unknown' |
|
||||
'SoftLeft' | 'SoftRight' |
|
||||
'Home' |
|
||||
'Back' |
|
||||
'Call' | 'EndCall' |
|
||||
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||
'Star' | 'Pound' | '*' | '#' |
|
||||
'DialUp' | 'DialDown' | 'DialLeft' | 'DialRight' | 'DialCenter' |
|
||||
'VolumeUp' | 'VolumeDown' |
|
||||
'Power' |
|
||||
'Camera' |
|
||||
'Clear' |
|
||||
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' |
|
||||
'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' |
|
||||
'Comma' | ',' |
|
||||
'Period' | '.' |
|
||||
'AltLeft' | 'AltRight' |
|
||||
'ShiftLeft' | 'ShiftRight' |
|
||||
'Tab' | '\t' |
|
||||
'Space' | ' ' |
|
||||
'Sym' |
|
||||
'Explorer' |
|
||||
'Envelop' |
|
||||
'Enter' | '\n' |
|
||||
'Del' |
|
||||
'Grave' |
|
||||
'Minus' | '-' |
|
||||
'Equals' | '=' |
|
||||
'LeftBracket' | '(' |
|
||||
'RightBracket' | ')' |
|
||||
'Backslash' | '\\' |
|
||||
'Semicolon' | ';' |
|
||||
'Apostrophe' | '`' |
|
||||
'Slash' | '/' |
|
||||
'At' |
|
||||
'Num' |
|
||||
'HeadsetHook' |
|
||||
'Focus' |
|
||||
'Plus' | '+' |
|
||||
'Menu' |
|
||||
'Notification' |
|
||||
'Search';
|
|
@ -7217,10 +7217,909 @@ export interface ElectronApplication {
|
|||
*/
|
||||
windows(): Array<Page>;}
|
||||
|
||||
export type AndroidElementInfo = {
|
||||
clazz: string;
|
||||
desc: string;
|
||||
res: string;
|
||||
pkg: string;
|
||||
text: string;
|
||||
bounds: { x: number, y: number, width: number, height: number };
|
||||
checkable: boolean;
|
||||
checked: boolean;
|
||||
clickable: boolean;
|
||||
enabled: boolean;
|
||||
focusable: boolean;
|
||||
focused: boolean;
|
||||
longClickable: boolean;
|
||||
scrollable: boolean;
|
||||
selected: boolean;
|
||||
};
|
||||
|
||||
export type AndroidSelector = {
|
||||
checkable?: boolean,
|
||||
checked?: boolean,
|
||||
clazz?: string | RegExp,
|
||||
clickable?: boolean,
|
||||
depth?: number,
|
||||
desc?: string | RegExp,
|
||||
enabled?: boolean,
|
||||
focusable?: boolean,
|
||||
focused?: boolean,
|
||||
hasChild?: { selector: AndroidSelector },
|
||||
hasDescendant?: { selector: AndroidSelector, maxDepth?: number },
|
||||
longClickable?: boolean,
|
||||
pkg?: string | RegExp,
|
||||
res?: string | RegExp,
|
||||
scrollable?: boolean,
|
||||
selected?: boolean,
|
||||
text?: string | RegExp,
|
||||
};
|
||||
|
||||
export type AndroidKey =
|
||||
'Unknown' |
|
||||
'SoftLeft' | 'SoftRight' |
|
||||
'Home' |
|
||||
'Back' |
|
||||
'Call' | 'EndCall' |
|
||||
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||
'Star' | 'Pound' | '*' | '#' |
|
||||
'DialUp' | 'DialDown' | 'DialLeft' | 'DialRight' | 'DialCenter' |
|
||||
'VolumeUp' | 'VolumeDown' |
|
||||
'Power' |
|
||||
'Camera' |
|
||||
'Clear' |
|
||||
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' |
|
||||
'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' |
|
||||
'Comma' | ',' |
|
||||
'Period' | '.' |
|
||||
'AltLeft' | 'AltRight' |
|
||||
'ShiftLeft' | 'ShiftRight' |
|
||||
'Tab' | '\t' |
|
||||
'Space' | ' ' |
|
||||
'Sym' |
|
||||
'Explorer' |
|
||||
'Envelop' |
|
||||
'Enter' | '\n' |
|
||||
'Del' |
|
||||
'Grave' |
|
||||
'Minus' | '-' |
|
||||
'Equals' | '=' |
|
||||
'LeftBracket' | '(' |
|
||||
'RightBracket' | ')' |
|
||||
'Backslash' | '\\' |
|
||||
'Semicolon' | ';' |
|
||||
'Apostrophe' | '`' |
|
||||
'Slash' | '/' |
|
||||
'At' |
|
||||
'Num' |
|
||||
'HeadsetHook' |
|
||||
'Focus' |
|
||||
'Plus' | '+' |
|
||||
'Menu' |
|
||||
'Notification' |
|
||||
'Search';
|
||||
|
||||
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
|
||||
export {};
|
||||
|
||||
|
||||
/**
|
||||
* Playwright has **experimental** support for Android automation. You can access android namespace via:
|
||||
*
|
||||
* ```js
|
||||
* const { _android } = require('playwright');
|
||||
* ```
|
||||
*
|
||||
* An example of the Android automation script would be:
|
||||
*
|
||||
* ```js
|
||||
* const { _android } = require('playwright');
|
||||
*
|
||||
* (async () => {
|
||||
* // Connect to the device.
|
||||
* const [device] = await playwright._android.devices();
|
||||
* console.log(`Model: ${device.model()}`);
|
||||
* console.log(`Serial: ${device.serial()}`);
|
||||
* // Take screenshot of the whole device.
|
||||
* await device.screenshot({ path: 'device.png' });
|
||||
*
|
||||
* {
|
||||
* // --------------------- WebView -----------------------
|
||||
*
|
||||
* // Launch an application with WebView.
|
||||
* await device.shell('am force-stop org.chromium.webview_shell');
|
||||
* await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
|
||||
* // Get the WebView.
|
||||
* const webview = await device.webView({ pkg: 'org.chromium.webview_shell' });
|
||||
*
|
||||
* // Fill the input box.
|
||||
* await device.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'github.com/microsoft/playwright');
|
||||
* await device.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter');
|
||||
*
|
||||
* // Work with WebView's page as usual.
|
||||
* const page = await webview.page();
|
||||
* await page.page.waitForNavigation({ url: /.*microsoft\/playwright.*\/ });
|
||||
* console.log(await page.title());
|
||||
* }
|
||||
*
|
||||
* {
|
||||
* // --------------------- Browser -----------------------
|
||||
*
|
||||
* // Launch Chrome browser.
|
||||
* await device.shell('am force-stop com.android.chrome');
|
||||
* const context = await device.launchBrowser();
|
||||
*
|
||||
* // Use BrowserContext as usual.
|
||||
* const page = await context.newPage();
|
||||
* await page.goto('https://webkit.org/');
|
||||
* console.log(await page.evaluate(() => window.location.href));
|
||||
* await page.screenshot({ path: 'page.png' });
|
||||
*
|
||||
* await context.close();
|
||||
* }
|
||||
*
|
||||
* // Close the device.
|
||||
* await device.close();
|
||||
* })();
|
||||
* ```
|
||||
*
|
||||
* Note that since you don't need Playwright to install web browsers when testing Android, you can omit browser download
|
||||
* via setting the following environment variable when installing Playwright:
|
||||
*
|
||||
* ```sh js
|
||||
* $ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i -D playwright
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
export interface Android {
|
||||
/**
|
||||
* Returns the list of detected Android devices.
|
||||
*/
|
||||
devices(): Promise<Array<AndroidDevice>>;
|
||||
|
||||
/**
|
||||
* This setting will change the default maximum time for all the methods accepting `timeout` option.
|
||||
* @param timeout Maximum time in milliseconds
|
||||
*/
|
||||
setDefaultTimeout(timeout: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* [AndroidDevice] represents a connected device, either real hardware or emulated. Devices can be obtained using
|
||||
* [android.devices()](https://playwright.dev/docs/api/class-android#androiddevices).
|
||||
*/
|
||||
export interface AndroidDevice {
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
on(event: 'webview', listener: (androidWebView: AndroidWebView) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
once(event: 'webview', listener: (androidWebView: AndroidWebView) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
addListener(event: 'webview', listener: (androidWebView: AndroidWebView) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
removeListener(event: 'webview', listener: (androidWebView: AndroidWebView) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
off(event: 'webview', listener: (androidWebView: AndroidWebView) => void): this;
|
||||
|
||||
/**
|
||||
* Disconnects from the device.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Drags the widget defined by `selector` towards `dest` point.
|
||||
* @param selector Selector to drag.
|
||||
* @param dest Point to drag to.
|
||||
* @param options
|
||||
*/
|
||||
drag(selector: AndroidSelector, dest: {
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}, options?: {
|
||||
/**
|
||||
* Optional speed of the drag in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Fills the specific `selector` input box with `text`.
|
||||
* @param selector Selector to fill.
|
||||
* @param text Text to be filled in the input box.
|
||||
* @param options
|
||||
*/
|
||||
fill(selector: AndroidSelector, text: string, options?: {
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Flings the widget defined by `selector` in the specified `direction`.
|
||||
* @param selector Selector to fling.
|
||||
* @param direction Fling direction.
|
||||
* @param options
|
||||
*/
|
||||
fling(selector: AndroidSelector, direction: "down"|"up"|"left"|"right", options?: {
|
||||
/**
|
||||
* Optional speed of the fling in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns information about a widget defined by `selector`.
|
||||
* @param selector Selector to return information about.
|
||||
*/
|
||||
info(selector: AndroidSelector): Promise<AndroidElementInfo>;
|
||||
|
||||
input: AndroidInput;
|
||||
|
||||
/**
|
||||
* Installs an apk on the device.
|
||||
* @param file Either a path to the apk file, or apk file content.
|
||||
* @param options
|
||||
*/
|
||||
installApk(file: string|Buffer, options?: {
|
||||
/**
|
||||
* Optional arguments to pass to the `shell:cmd package install` call. Defaults to `-r -t -S`.
|
||||
*/
|
||||
args?: Array<string>;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Launches Chrome browser on the device, and returns its persistent context.
|
||||
* @param options
|
||||
*/
|
||||
launchBrowser(options?: {
|
||||
/**
|
||||
* Whether to automatically download all the attachments. Defaults to `false` where all the downloads are canceled.
|
||||
*/
|
||||
acceptDownloads?: boolean;
|
||||
|
||||
/**
|
||||
* Toggles bypassing page's Content-Security-Policy.
|
||||
*/
|
||||
bypassCSP?: boolean;
|
||||
|
||||
/**
|
||||
* Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See
|
||||
* [page.emulateMedia([options])](https://playwright.dev/docs/api/class-page#pageemulatemediaoptions) for more details.
|
||||
* Defaults to '`light`'.
|
||||
*/
|
||||
colorScheme?: "light"|"dark"|"no-preference";
|
||||
|
||||
/**
|
||||
* Optional package name to launch instead of default Chrome for Android.
|
||||
*/
|
||||
command?: string;
|
||||
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to `1`.
|
||||
*/
|
||||
deviceScaleFactor?: number;
|
||||
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. All header values must be strings.
|
||||
*/
|
||||
extraHTTPHeaders?: { [key: string]: string; };
|
||||
|
||||
geolocation?: {
|
||||
/**
|
||||
* Latitude between -90 and 90.
|
||||
*/
|
||||
latitude: number;
|
||||
|
||||
/**
|
||||
* Longitude between -180 and 180.
|
||||
*/
|
||||
longitude: number;
|
||||
|
||||
/**
|
||||
* Non-negative accuracy value. Defaults to `0`.
|
||||
*/
|
||||
accuracy?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
hasTouch?: boolean;
|
||||
|
||||
/**
|
||||
* Credentials for [HTTP authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
|
||||
*/
|
||||
httpCredentials?: {
|
||||
username: string;
|
||||
|
||||
password: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether to ignore HTTPS errors during navigation. Defaults to `false`.
|
||||
*/
|
||||
ignoreHTTPSErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the `meta viewport` tag is taken into account and touch events are enabled. Defaults to `false`. Not supported
|
||||
* in Firefox.
|
||||
*/
|
||||
isMobile?: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not to enable JavaScript in the context. Defaults to `true`.
|
||||
*/
|
||||
javaScriptEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* Specify user locale, for example `en-GB`, `de-DE`, etc. Locale will affect `navigator.language` value, `Accept-Language`
|
||||
* request header value as well as number and date formatting rules.
|
||||
*/
|
||||
locale?: string;
|
||||
|
||||
/**
|
||||
* Logger sink for Playwright logging.
|
||||
*/
|
||||
logger?: Logger;
|
||||
|
||||
/**
|
||||
* Whether to emulate network being offline. Defaults to `false`.
|
||||
*/
|
||||
offline?: boolean;
|
||||
|
||||
/**
|
||||
* A list of permissions to grant to all pages in this context. See
|
||||
* [browserContext.grantPermissions(permissions[, options])](https://playwright.dev/docs/api/class-browsercontext#browsercontextgrantpermissionspermissions-options)
|
||||
* for more details.
|
||||
*/
|
||||
permissions?: Array<string>;
|
||||
|
||||
/**
|
||||
* Enables [HAR](http://www.softwareishard.com/blog/har-12-spec) recording for all pages into `recordHar.path` file. If not
|
||||
* specified, the HAR is not recorded. Make sure to await
|
||||
* [browserContext.close()](https://playwright.dev/docs/api/class-browsercontext#browsercontextclose) for the HAR to be
|
||||
* saved.
|
||||
*/
|
||||
recordHar?: {
|
||||
/**
|
||||
* Optional setting to control whether to omit request content from the HAR. Defaults to `false`.
|
||||
*/
|
||||
omitContent?: boolean;
|
||||
|
||||
/**
|
||||
* Path on the filesystem to write the HAR file to.
|
||||
*/
|
||||
path: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables video recording for all pages into `recordVideo.dir` directory. If not specified videos are not recorded. Make
|
||||
* sure to await [browserContext.close()](https://playwright.dev/docs/api/class-browsercontext#browsercontextclose) for
|
||||
* videos to be saved.
|
||||
*/
|
||||
recordVideo?: {
|
||||
/**
|
||||
* Path to the directory to put videos into.
|
||||
*/
|
||||
dir: string;
|
||||
|
||||
/**
|
||||
* Optional dimensions of the recorded videos. If not specified the size will be equal to `viewport` scaled down to fit
|
||||
* into 800x800. If `viewport` is not configured explicitly the video size defaults to 800x450. Actual picture of each page
|
||||
* will be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
size?: {
|
||||
/**
|
||||
* Video frame width.
|
||||
*/
|
||||
width: number;
|
||||
|
||||
/**
|
||||
* Video frame height.
|
||||
*/
|
||||
height: number;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the timezone of the context. See
|
||||
* [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1)
|
||||
* for a list of supported timezone IDs.
|
||||
*/
|
||||
timezoneId?: string;
|
||||
|
||||
/**
|
||||
* Specific user agent to use in this context.
|
||||
*/
|
||||
userAgent?: string;
|
||||
|
||||
/**
|
||||
* **DEPRECATED** Use `recordVideo` instead.
|
||||
* @deprecated
|
||||
*/
|
||||
videoSize?: {
|
||||
/**
|
||||
* Video frame width.
|
||||
*/
|
||||
width: number;
|
||||
|
||||
/**
|
||||
* Video frame height.
|
||||
*/
|
||||
height: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* **DEPRECATED** Use `recordVideo` instead.
|
||||
* @deprecated
|
||||
*/
|
||||
videosPath?: string;
|
||||
|
||||
/**
|
||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||
*/
|
||||
viewport?: null|{
|
||||
/**
|
||||
* page width in pixels.
|
||||
*/
|
||||
width: number;
|
||||
|
||||
/**
|
||||
* page height in pixels.
|
||||
*/
|
||||
height: number;
|
||||
};
|
||||
}): Promise<ChromiumBrowserContext>;
|
||||
|
||||
/**
|
||||
* Performs a long tap on the widget defined by `selector`.
|
||||
* @param selector Selector to tap on.
|
||||
* @param options
|
||||
*/
|
||||
longTap(selector: AndroidSelector, options?: {
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Device model.
|
||||
*/
|
||||
model(): string;
|
||||
|
||||
/**
|
||||
* Launches a process in the shell on the device and returns a socket to communicate with the launched process.
|
||||
* @param command
|
||||
*/
|
||||
open(command: string): Promise<AndroidSocket>;
|
||||
|
||||
/**
|
||||
* Pinches the widget defined by `selector` in the closing direction.
|
||||
* @param selector Selector to pinch close.
|
||||
* @param percent The size of the pinch as a percentage of the widget's size.
|
||||
* @param options
|
||||
*/
|
||||
pinchClose(selector: AndroidSelector, percent: number, options?: {
|
||||
/**
|
||||
* Optional speed of the pinch in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Pinches the widget defined by `selector` in the open direction.
|
||||
* @param selector Selector to pinch open.
|
||||
* @param percent The size of the pinch as a percentage of the widget's size.
|
||||
* @param options
|
||||
*/
|
||||
pinchOpen(selector: AndroidSelector, percent: number, options?: {
|
||||
/**
|
||||
* Optional speed of the pinch in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Presses the specific `key` in the widget defined by `selector`.
|
||||
* @param selector Selector to press the key in.
|
||||
* @param key The key to press.
|
||||
* @param options
|
||||
*/
|
||||
press(selector: AndroidSelector, key: AndroidKey, options?: {
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Copies a file to the device.
|
||||
* @param file Either a path to the file, or file content.
|
||||
* @param path Path to the file on the device.
|
||||
* @param options
|
||||
*/
|
||||
push(file: string|Buffer, path: string, options?: {
|
||||
/**
|
||||
* Optional file mode, defaults to `644` (`rw-r--r--`).
|
||||
*/
|
||||
mode?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns the buffer with the captured screenshot of the device.
|
||||
* @param options
|
||||
*/
|
||||
screenshot(options?: {
|
||||
/**
|
||||
* The file path to save the image to. If `path` is a relative path, then it is resolved relative to the current working
|
||||
* directory. If no path is provided, the image won't be saved to the disk.
|
||||
*/
|
||||
path?: string;
|
||||
}): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Scrolls the widget defined by `selector` in the specified `direction`.
|
||||
* @param selector Selector to scroll.
|
||||
* @param direction Scroll direction.
|
||||
* @param percent Distance to scroll as a percentage of the widget's size.
|
||||
* @param options
|
||||
*/
|
||||
scroll(selector: AndroidSelector, direction: "down"|"up"|"left"|"right", percent: number, options?: {
|
||||
/**
|
||||
* Optional speed of the scroll in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Device serial number.
|
||||
*/
|
||||
serial(): string;
|
||||
|
||||
/**
|
||||
* This setting will change the default maximum time for all the methods accepting `timeout` option.
|
||||
* @param timeout Maximum time in milliseconds
|
||||
*/
|
||||
setDefaultTimeout(timeout: number): void;
|
||||
|
||||
/**
|
||||
* Executes a shell command on the device and returns its output.
|
||||
* @param command Shell command to execute.
|
||||
*/
|
||||
shell(command: string): Promise<Buffer>;
|
||||
|
||||
/**
|
||||
* Swipes the widget defined by `selector` in the specified `direction`.
|
||||
* @param selector Selector to swipe.
|
||||
* @param direction Swipe direction.
|
||||
* @param percent Distance to swipe as a percentage of the widget's size.
|
||||
* @param options
|
||||
*/
|
||||
swipe(selector: AndroidSelector, direction: "down"|"up"|"left"|"right", percent: number, options?: {
|
||||
/**
|
||||
* Optional speed of the swipe in pixels per second.
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Taps on the widget defined by `selector`.
|
||||
* @param selector Selector to tap on.
|
||||
* @param options
|
||||
*/
|
||||
tap(selector: AndroidSelector, options?: {
|
||||
/**
|
||||
* Optional duration of the tap in milliseconds.
|
||||
*/
|
||||
duration?: number;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Waits for the specific `selector` to either appear or disappear, depending on the `state`.
|
||||
* @param selector Selector to wait for.
|
||||
* @param options
|
||||
*/
|
||||
wait(selector: AndroidSelector, options?: {
|
||||
/**
|
||||
* Optional state. Can be either:
|
||||
* - default - wait for element to be present.
|
||||
* - `'gone'` - wait for element to not be present.
|
||||
*/
|
||||
state?: "gone";
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Emitted when a new WebView instance is detected.
|
||||
*/
|
||||
waitForEvent(event: 'webview', optionsOrPredicate?: { predicate?: (androidWebView: AndroidWebView) => boolean, timeout?: number } | ((androidWebView: AndroidWebView) => boolean)): Promise<AndroidWebView>;
|
||||
|
||||
|
||||
/**
|
||||
* This method waits until [AndroidWebView] matching the `selector` is opened and returns it. If there is already an open
|
||||
* [AndroidWebView] matching the `selector`, returns immediately.
|
||||
* @param selector
|
||||
* @param options
|
||||
*/
|
||||
webView(selector: {
|
||||
/**
|
||||
* Package identifier.
|
||||
*/
|
||||
pkg: string;
|
||||
}, options?: {
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [androidDevice.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-androiddevice#androiddevicesetdefaulttimeouttimeout)
|
||||
* method.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<AndroidWebView>;
|
||||
|
||||
/**
|
||||
* Currently open WebViews.
|
||||
*/
|
||||
webViews(): Array<AndroidWebView>;
|
||||
}
|
||||
|
||||
export interface AndroidInput {
|
||||
/**
|
||||
* Performs a drag between `from` and `to` points.
|
||||
* @param from The start point of the drag.
|
||||
* @param to The end point of the drag.
|
||||
* @param steps The number of steps in the drag. Each step takes 5 milliseconds to complete.
|
||||
*/
|
||||
drag(from: {
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}, to: {
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}, steps: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Presses the `key`.
|
||||
* @param key Key to press.
|
||||
*/
|
||||
press(key: AndroidKey): Promise<void>;
|
||||
|
||||
/**
|
||||
* Swipes following the path defined by `segments`.
|
||||
* @param from The point to start swiping from.
|
||||
* @param segments Points following the `from` point in the swipe gesture.
|
||||
* @param steps The number of steps for each segment. Each step takes 5 milliseconds to complete, so 100 steps means half a second per each segment.
|
||||
*/
|
||||
swipe(from: {
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}, segments: Array<{
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}>, steps: number): Promise<void>;
|
||||
|
||||
/**
|
||||
* Taps at the specified `point`.
|
||||
* @param point The point to tap at.
|
||||
*/
|
||||
tap(point: {
|
||||
x: number;
|
||||
|
||||
y: number;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Types `text` into currently focused widget.
|
||||
* @param text Text to type.
|
||||
*/
|
||||
type(text: string): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* [AndroidSocket] is a way to communicate with a process launched on the [AndroidDevice]. Use
|
||||
* [androidDevice.open(command)](https://playwright.dev/docs/api/class-androiddevice#androiddeviceopencommand) to open a
|
||||
* socket.
|
||||
*/
|
||||
export interface AndroidSocket {
|
||||
/**
|
||||
* Emitted when the socket is closed.
|
||||
*/
|
||||
on(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when data is available to read from the socket.
|
||||
*/
|
||||
on(event: 'data', listener: (buffer: Buffer) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the socket is closed.
|
||||
*/
|
||||
once(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when data is available to read from the socket.
|
||||
*/
|
||||
once(event: 'data', listener: (buffer: Buffer) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the socket is closed.
|
||||
*/
|
||||
addListener(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when data is available to read from the socket.
|
||||
*/
|
||||
addListener(event: 'data', listener: (buffer: Buffer) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the socket is closed.
|
||||
*/
|
||||
removeListener(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when data is available to read from the socket.
|
||||
*/
|
||||
removeListener(event: 'data', listener: (buffer: Buffer) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the socket is closed.
|
||||
*/
|
||||
off(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when data is available to read from the socket.
|
||||
*/
|
||||
off(event: 'data', listener: (buffer: Buffer) => void): this;
|
||||
|
||||
/**
|
||||
* Closes the socket.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Writes some `data` to the socket.
|
||||
* @param data Data to write.
|
||||
*/
|
||||
write(data: Buffer): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* [AndroidWebView] represents a WebView open on the [AndroidDevice]. WebView is usually obtained using
|
||||
* [androidDevice.webView(selector[, options])](https://playwright.dev/docs/api/class-androiddevice#androiddevicewebviewselector-options).
|
||||
*/
|
||||
export interface AndroidWebView {
|
||||
/**
|
||||
* Emitted when the WebView is closed.
|
||||
*/
|
||||
on(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the WebView is closed.
|
||||
*/
|
||||
once(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the WebView is closed.
|
||||
*/
|
||||
addListener(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the WebView is closed.
|
||||
*/
|
||||
removeListener(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when the WebView is closed.
|
||||
*/
|
||||
off(event: 'close', listener: () => void): this;
|
||||
|
||||
/**
|
||||
* Connects to the WebView and returns a regular Playwright [Page] to interact with.
|
||||
*/
|
||||
page(): Promise<Page>;
|
||||
|
||||
/**
|
||||
* WebView process PID.
|
||||
*/
|
||||
pid(): number;
|
||||
|
||||
/**
|
||||
* WebView package identifier.
|
||||
*/
|
||||
pkg(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* - extends: [EventEmitter]
|
||||
*
|
||||
|
|
|
@ -230,5 +230,87 @@ export interface ElectronApplication {
|
|||
evaluateHandle<R>(pageFunction: PageFunctionOn<typeof import('electron'), void, R>, arg?: any): Promise<SmartHandle<R>>;
|
||||
}
|
||||
|
||||
export type AndroidElementInfo = {
|
||||
clazz: string;
|
||||
desc: string;
|
||||
res: string;
|
||||
pkg: string;
|
||||
text: string;
|
||||
bounds: { x: number, y: number, width: number, height: number };
|
||||
checkable: boolean;
|
||||
checked: boolean;
|
||||
clickable: boolean;
|
||||
enabled: boolean;
|
||||
focusable: boolean;
|
||||
focused: boolean;
|
||||
longClickable: boolean;
|
||||
scrollable: boolean;
|
||||
selected: boolean;
|
||||
};
|
||||
|
||||
export type AndroidSelector = {
|
||||
checkable?: boolean,
|
||||
checked?: boolean,
|
||||
clazz?: string | RegExp,
|
||||
clickable?: boolean,
|
||||
depth?: number,
|
||||
desc?: string | RegExp,
|
||||
enabled?: boolean,
|
||||
focusable?: boolean,
|
||||
focused?: boolean,
|
||||
hasChild?: { selector: AndroidSelector },
|
||||
hasDescendant?: { selector: AndroidSelector, maxDepth?: number },
|
||||
longClickable?: boolean,
|
||||
pkg?: string | RegExp,
|
||||
res?: string | RegExp,
|
||||
scrollable?: boolean,
|
||||
selected?: boolean,
|
||||
text?: string | RegExp,
|
||||
};
|
||||
|
||||
export type AndroidKey =
|
||||
'Unknown' |
|
||||
'SoftLeft' | 'SoftRight' |
|
||||
'Home' |
|
||||
'Back' |
|
||||
'Call' | 'EndCall' |
|
||||
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||
'Star' | 'Pound' | '*' | '#' |
|
||||
'DialUp' | 'DialDown' | 'DialLeft' | 'DialRight' | 'DialCenter' |
|
||||
'VolumeUp' | 'VolumeDown' |
|
||||
'Power' |
|
||||
'Camera' |
|
||||
'Clear' |
|
||||
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' |
|
||||
'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' |
|
||||
'Comma' | ',' |
|
||||
'Period' | '.' |
|
||||
'AltLeft' | 'AltRight' |
|
||||
'ShiftLeft' | 'ShiftRight' |
|
||||
'Tab' | '\t' |
|
||||
'Space' | ' ' |
|
||||
'Sym' |
|
||||
'Explorer' |
|
||||
'Envelop' |
|
||||
'Enter' | '\n' |
|
||||
'Del' |
|
||||
'Grave' |
|
||||
'Minus' | '-' |
|
||||
'Equals' | '=' |
|
||||
'LeftBracket' | '(' |
|
||||
'RightBracket' | ')' |
|
||||
'Backslash' | '\\' |
|
||||
'Semicolon' | ';' |
|
||||
'Apostrophe' | '`' |
|
||||
'Slash' | '/' |
|
||||
'At' |
|
||||
'Num' |
|
||||
'HeadsetHook' |
|
||||
'Focus' |
|
||||
'Plus' | '+' |
|
||||
'Menu' |
|
||||
'Notification' |
|
||||
'Search';
|
||||
|
||||
// This is required to not export everything by default. See https://github.com/Microsoft/TypeScript/issues/19545#issuecomment-340490459
|
||||
export {};
|
||||
|
|
Загрузка…
Ссылка в новой задаче