mirror of
https://github.com/appium/appium.git
synced 2026-05-03 00:41:07 -05:00
Merge pull request #2449 from bootstraponline/1.0-beta
Document appium bindings & remove incorrect docs
This commit is contained in:
@@ -0,0 +1,668 @@
|
||||
# Appium Client Libraries
|
||||
|
||||
Appium has libraries for:
|
||||
|
||||
Language | Source
|
||||
:--|--:
|
||||
[Ruby][rubygems] | [GitHub](https://github.com/appium/ruby_lib)
|
||||
[Python][pypi] | [GitHub](https://github.com/appium/python-client)
|
||||
[Java][maven] | [GitHub](https://github.com/appium/java-client)
|
||||
[JavaScript][npm] | [GitHub](https://github.com/admc/wd)
|
||||
[PHP][php] | [GitHub](https://github.com/appium/php-client)
|
||||
[C#][nuget] | [GitHub](https://github.com/appium/appium-dotnet-driver)
|
||||
|
||||
[rubygems]: http://rubygems.org/gems/appium_lib
|
||||
[pypi]: https://pypi.python.org/pypi/Appium-Python-Client
|
||||
[maven]: https://search.maven.org/#search%7Cga%7C1%7Cg%3Aio.appium%20a%3Ajava-client
|
||||
[npm]: https://www.npmjs.org/package/wd
|
||||
[php]: https://github.com/appium/php-client
|
||||
[nuget]: http://www.nuget.org/packages/Appium.WebDriver/
|
||||
|
||||
Note that some methods such as `endTestCoverage()` and `complexFind()` are
|
||||
not generally useful. Proper coverage support will be added once [this issue](https://github.com/appium/appium/issues/2448)
|
||||
is resolved. `complexFind()` will be removed once [this issue](https://github.com/appium/appium/issues/2264)
|
||||
is resolved. If you want to use them anyway, consult the documentation for the bindings on GitHub.
|
||||
|
||||
## Lock
|
||||
|
||||
Lock the screen.
|
||||
|
||||
```ruby
|
||||
lock 5
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.lock(5)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.lockScreen(3);
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.LockDevice(3);
|
||||
```
|
||||
|
||||
## Background app
|
||||
|
||||
Send the currently active app to the background.
|
||||
|
||||
```ruby
|
||||
background_app 5
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.background_app(5)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.runAppInBackground(5);
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.BackgroundApp(5);
|
||||
```
|
||||
|
||||
## Hide Keyboard (iOS only)
|
||||
|
||||
Hide the keyboard on iOS
|
||||
|
||||
```ruby
|
||||
hide_keyboard
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.hide_keyboard()
|
||||
```
|
||||
|
||||
```java
|
||||
driver.hideKeyboard();
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.HideKeyboard("Done");
|
||||
```
|
||||
|
||||
## Is installed
|
||||
|
||||
Check if an app is installed
|
||||
|
||||
```ruby
|
||||
is_installed? "com.example.android.apis"
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.is_app_installed('com.example.android.apis')
|
||||
```
|
||||
|
||||
```java
|
||||
driver.isAppInstalled("com.example.android.apis")
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.IsAppInstalled("com.example.android.apis-");
|
||||
```
|
||||
|
||||
## Install App
|
||||
|
||||
Install an app to the device.
|
||||
|
||||
```ruby
|
||||
install 'path/to/my.apk'
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.install_app('path/to/my.apk')
|
||||
```
|
||||
|
||||
```java
|
||||
driver.installApp("path/to/my.apk")
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.InstallApp("path/to/my.apk");
|
||||
```
|
||||
|
||||
## Remove App
|
||||
|
||||
Remove an app from the device.
|
||||
|
||||
```ruby
|
||||
remove 'com.example.android.apis'
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.remove_app('com.example.android.apis')
|
||||
```
|
||||
|
||||
```java
|
||||
driver.removeApp("com.example.android.apis")
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.RemoveApp("com.example.android.apis");
|
||||
```
|
||||
|
||||
## Shake
|
||||
|
||||
Simulate the device shaking.
|
||||
|
||||
```ruby
|
||||
shake
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.shake()
|
||||
```
|
||||
|
||||
```java
|
||||
driver.shake()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.ShakeDevice();
|
||||
```
|
||||
|
||||
## Close app
|
||||
|
||||
Close the app
|
||||
|
||||
```ruby
|
||||
close_app
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.close_app();
|
||||
```
|
||||
|
||||
```java
|
||||
driver.closeApp()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.CloseApp();
|
||||
```
|
||||
|
||||
## Launch
|
||||
|
||||
Launch the app
|
||||
|
||||
```ruby
|
||||
launch
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.launch_app()
|
||||
```
|
||||
|
||||
```java
|
||||
driver.launchApp()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.LaunchApp();
|
||||
```
|
||||
|
||||
## Reset
|
||||
|
||||
Reset the app.
|
||||
|
||||
```ruby
|
||||
reset
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.reset()
|
||||
```
|
||||
|
||||
```java
|
||||
driver.resetApp()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.ResetApp();
|
||||
```
|
||||
|
||||
## Available Contexts
|
||||
|
||||
List all available contexts
|
||||
|
||||
```ruby
|
||||
context_array = available_contexts
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.contexts
|
||||
```
|
||||
|
||||
```java
|
||||
driver.getContextHandles()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.GetContexts()
|
||||
```
|
||||
|
||||
## Current context
|
||||
|
||||
List the current context
|
||||
|
||||
|
||||
```ruby
|
||||
context = current_context
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.current_context
|
||||
```
|
||||
|
||||
```java
|
||||
driver.getContext()
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.GetContext()
|
||||
```
|
||||
|
||||
## Switch to default context
|
||||
|
||||
Change the context to the default.
|
||||
|
||||
```ruby
|
||||
switch_to_default_context
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.switch_to.context(None)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.context();
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.SetContext();
|
||||
```
|
||||
|
||||
## App Strings
|
||||
|
||||
Get the app's strings.
|
||||
|
||||
```ruby
|
||||
strings = app_strings
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.app_strings
|
||||
```
|
||||
|
||||
```java
|
||||
driver.getAppString();
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.GetAppStrings();
|
||||
```
|
||||
|
||||
## Key Event
|
||||
|
||||
Send a key event to the device.
|
||||
|
||||
```ruby
|
||||
key_event 176
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.keyevent(176)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.sendKeyEvent(AndroidKeyCode.HOME);
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.KeyEvent("176");
|
||||
```
|
||||
|
||||
## Current Activity
|
||||
|
||||
Android only. Get the current activity.
|
||||
|
||||
```ruby
|
||||
current_activity
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.current_activity
|
||||
```
|
||||
|
||||
```java
|
||||
driver.currentActivity();
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.GetCurrentActivity();
|
||||
```
|
||||
|
||||
## TouchAction / MultiTouchAction
|
||||
|
||||
An API for generating touch actions. This section of the documentation will be
|
||||
expanded upon soon.
|
||||
|
||||
```ruby
|
||||
touch_action = Appium::TouchAction.new
|
||||
element = find_element :name, 'Buttons, Various uses of UIButton'
|
||||
touch_action.press(element: element, x: 10, y: 10).perform
|
||||
```
|
||||
|
||||
```python
|
||||
self._touch_action.tap(element, 10, 10)
|
||||
```
|
||||
|
||||
```java
|
||||
TouchAction action = new TouchAction(driver)
|
||||
.press(mapview, 10, 10)
|
||||
.release().
|
||||
perform();
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
var touchAction1 = new TouchActions(this);
|
||||
touchAction1.Down(10, 10).Up(10, 10);
|
||||
|
||||
var multiTouchAction = new MultiTouchAction(this);
|
||||
multiTouchAction.Add(touchAction1);
|
||||
|
||||
PerformMultiTouchAction(multiTouchAction);
|
||||
```
|
||||
|
||||
## Swipe
|
||||
|
||||
Simulate a user swipe.
|
||||
|
||||
```ruby
|
||||
swipe start_x: 75, start_y: 500, end_x: 75, end_y: 0, duration: 0.8
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.swipe(75, 500, 75, 0, 0.8)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.swipe(75, 500, 75, 0, 800)
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
todo: c#
|
||||
```
|
||||
|
||||
## Pinch
|
||||
|
||||
Pinch the screen.
|
||||
|
||||
```ruby
|
||||
pinch 75
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.pinch(element=el)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.pinch(element);
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.Pinch(25, 25)
|
||||
```
|
||||
|
||||
## Zoom
|
||||
|
||||
Zoom the screen.
|
||||
|
||||
```ruby
|
||||
zoom 200
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.zoom(element=el)
|
||||
```
|
||||
|
||||
```java
|
||||
driver.zoom(element);
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.Zoom(100, 200);
|
||||
```
|
||||
|
||||
## Pull file
|
||||
|
||||
Pulls a file from the device.
|
||||
|
||||
```ruby
|
||||
pull_file 'Library/AddressBook/AddressBook.sqlitedb'
|
||||
```
|
||||
|
||||
```python
|
||||
self.driver.pull_file('Library/AddressBook/AddressBook.sqlitedb')
|
||||
```
|
||||
|
||||
```java
|
||||
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb");
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.PullFile("Library/AddressBook/AddressBook.sqlitedb");
|
||||
```
|
||||
|
||||
## Push File
|
||||
|
||||
Pushes a file to the device.
|
||||
|
||||
```ruby
|
||||
data = "some data for the file"
|
||||
path = "/data/local/tmp/file.txt"
|
||||
push_file path, data
|
||||
```
|
||||
|
||||
```python
|
||||
data = "some data for the file"
|
||||
path = "/data/local/tmp/file.txt"
|
||||
self.driver.push_file(path, data.encode('base64'))
|
||||
```
|
||||
|
||||
```java
|
||||
byte[] data = Base64.encodeBase64("some data for the file".getBytes());
|
||||
String path = "/data/local/tmp/file.txt";
|
||||
driver.pushFile(path, data)
|
||||
```
|
||||
|
||||
```javascript
|
||||
todo: javascript
|
||||
```
|
||||
|
||||
```php
|
||||
todo: php
|
||||
```
|
||||
|
||||
```csharp
|
||||
driver.PushFile("/data/local/tmp/file.txt", "some data for the file");
|
||||
```
|
||||
|
||||
## Appium Desktop Apps
|
||||
|
||||
Appium's desktop app supports OS X and Windows.
|
||||
|
||||
- [Appium.app for OS X][bitbucket]
|
||||
- [Appium.exe for Windows][bitbucket]
|
||||
|
||||
[bitbucket]: https://bitbucket.org/appium/appium.app/downloads/
|
||||
+1
-137
@@ -2,11 +2,7 @@
|
||||
|
||||
Appium supports a subset of the WebDriver locator strategies:
|
||||
|
||||
* find by "tag name" (i.e., ui component type)
|
||||
* find by "name" (i.e., the text, label, or developer-generated ID a.k.a
|
||||
'accessibilityIdentifier' of an element)
|
||||
NOTE: the "name" locator strategy will be deprecated on mobile devices,
|
||||
and will not be a part of Appium v1.0
|
||||
* find by "class" (i.e., ui component type)
|
||||
* find by "xpath" (i.e., an abstract representation of a path to an element,
|
||||
with certain constraints)
|
||||
|
||||
@@ -19,143 +15,11 @@ search using the UiAutomator Api (Android-only)
|
||||
* `accessibility id`: a string corresponding to a recursive element search
|
||||
using the Id/Name that the native Accessibility options utilize.
|
||||
|
||||
## Tag name mapping
|
||||
|
||||
You can use the direct UIAutomation component type name for the tag name,
|
||||
or use the simplified mapping (used in some examples below) found here:
|
||||
|
||||
https://github.com/appium/appium-uiauto/blob/master/uiauto/lib/mechanic.js#L30
|
||||
|
||||
## Issues
|
||||
|
||||
There's a known issue with table cell elements becoming invalidated before
|
||||
there's time to interact with them. We're working on a fix
|
||||
|
||||
## Examples
|
||||
|
||||
### Find all the UIAButtons on the screen
|
||||
|
||||
WD.js:
|
||||
|
||||
```js
|
||||
driver.elementsByTagName('button', function(err, buttons) {
|
||||
// tap all the buttons
|
||||
var tapNextButton = function() {
|
||||
var button = buttons.shift();
|
||||
if (typeof button !== "undefined") {
|
||||
button.click(function(err) {
|
||||
tapNextButton();
|
||||
})
|
||||
} else {
|
||||
driver.quit();
|
||||
}
|
||||
}
|
||||
tapNextButton();
|
||||
});
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
buttons = @driver.find_elements :tag_name, :button
|
||||
buttons.each { |b| b.click }
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
[button.click() for button in driver.find_elements_by_tag_name('button')]
|
||||
```
|
||||
|
||||
### Find the element with the text (or accessibilityIdentifier) "Go"
|
||||
|
||||
WD.js:
|
||||
|
||||
```js
|
||||
driver.elementByName('Go', function(err, el) {
|
||||
el.tap(function(err) {
|
||||
driver.quit();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
@driver.find_element(:name, 'Go').click
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
driver.find_element_by_name('Go').click()
|
||||
```
|
||||
|
||||
### Find the nav bar text element where the text begins with "Hi, "
|
||||
|
||||
WD.js:
|
||||
|
||||
```js
|
||||
driver.elementByXpath('//navigationBar/text[contains(@value, "Hi, ")]', function(err, el) {
|
||||
el.text(function(err, text) {
|
||||
console.log(text);
|
||||
driver.quit();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
@driver.find_element :xpath, '//navigationBar/text[contains(@value, "Hi, ")]'
|
||||
```
|
||||
|
||||
### Find an element by tagName
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
driver.findElement(By.tagName("button")).sendKeys("Hi");
|
||||
|
||||
WebELement element = findElement(By.tagName("button"));
|
||||
element.sendKeys("Hi");
|
||||
|
||||
List<WebElement> elems = findElements(By.tagName("button"));
|
||||
elems.get(0).sendKeys("Hi");
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
driver.find_elements_by_tag_name('tableCell')[5].click()
|
||||
```
|
||||
|
||||
### Using the "-ios uiautomation" locator strategy
|
||||
|
||||
WD.js:
|
||||
|
||||
```js
|
||||
driver.element('-ios uiautomation', '.elements()[1].cells()[2]').getAttribute('name');
|
||||
```
|
||||
|
||||
### Using the "-android uiautomator" locator strategy
|
||||
|
||||
WD.js:
|
||||
|
||||
```js
|
||||
driver.element('-android uiautomator', 'new UiSelector().clickable(true)').getAttribute('name');
|
||||
```
|
||||
|
||||
### Pull to refresh using a swipe gesture
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
js_snippet = "mobile: swipe"
|
||||
args = {'startX':0.5, 'startY':0.2, 'startX':0.5, 'startY':0.95, 'tapCount':1, 'duration':10}
|
||||
driver.execute_script(js_snippet, args)
|
||||
```
|
||||
|
||||
## Using The Appium Inspector To Locate Elements
|
||||
|
||||
Appium provides you with a neat tool that allows you to find the the elements
|
||||
|
||||
@@ -1,369 +0,0 @@
|
||||
# Automating mobile gestures
|
||||
|
||||
While the Selenium WebDriver spec has support for certain kinds of mobile
|
||||
interaction, its parameters are not always easily mappable to the
|
||||
functionality that the underlying device automation (like UIAutomation in the
|
||||
case of iOS) provides. To that end, Appium augments the WebDriver spec with
|
||||
extra commands and parameters for mobile gestures:
|
||||
|
||||
* **tap** (on screen or on element) with options:
|
||||
* how many fingers
|
||||
* how long to tap
|
||||
* how many taps
|
||||
* where precisely to tap on the screen or element
|
||||
* **flick** (on screen or on element) with options:
|
||||
* how many fingers
|
||||
* where to start the flick on screen or element
|
||||
* where to end the flick on screen or element
|
||||
* **swipe/drag** (on screen or on element) with options:
|
||||
* how many fingers
|
||||
* how long the swipe/drag takes in seconds
|
||||
* where to start the swipe on screen or element
|
||||
* where to end the swipe on screen or element
|
||||
* **scroll to** (element)
|
||||
* **slider**
|
||||
* **shake**
|
||||
* **longTap** (element)
|
||||
* set the **orientation** with option:
|
||||
* new orientation (landscape or portrait)
|
||||
|
||||
## JSON Wire Protocol server extensions
|
||||
|
||||
Here are the endpoints with which we have implemented these additions to the
|
||||
spec.
|
||||
|
||||
**Note on coordinates:** All the X and Y parameters listed below can be used
|
||||
in two ways. If they are between 0 and 1 (e.g., 0.5), they are taken to be
|
||||
percentage of screen or element size. In other words,
|
||||
`{x: 0.5, y: 0.25}` means a coordinate that is 50% from the left side of the
|
||||
screen/element, and 25% from the top of the screen/element. If the values are
|
||||
greater than 1, they are taken as pixels. So, `{x: 100,
|
||||
y: 300}` means a coordinate that is 100 pixels from the left and 300 from
|
||||
the top of the screen/element.
|
||||
|
||||
**Note on performing actions on screen vs elements:** These methods all take
|
||||
an optional `element` parameter. If present, this is taken to be the ID of an
|
||||
element which has already been retrieved. So in this case,
|
||||
the coordinates will be taken to refer to the rectangle of that element only
|
||||
. So `{x: 0.5, y: 0.5, element: '3'}` means "the exact middle point of the
|
||||
element with ID '3'".
|
||||
|
||||
* `POST session/:sessionId/touch/tap` - perform a tap on the screen or an element
|
||||
* URL Parameter: sessionId of session to route to
|
||||
* JSON parameters:
|
||||
* `tapCount` (optional, default `1`): how many times to tap
|
||||
* `touchCount` (optional, default `1`): how many fingers to tap with
|
||||
* `duration` (optional, default `0.1`): how long (in seconds) to tap
|
||||
* `x` (optional, default `0.5`): x coordinate to tap (in pixels or relative units)
|
||||
* `y` (optional, default `0.5`): y coordinate to tap (in pixels or relative units)
|
||||
* `element` (optional): ID of element to scope this command to
|
||||
* `POST session:/sessionId/touch/flick_precise` - perform a flick on the screen or an element
|
||||
* URL Parameter: sessionId of session to route to
|
||||
* JSON parameters:
|
||||
* `touchCount` (optional, default `1`): how many fingers to flick with
|
||||
* `startX` (optional, default `0.5`): x coordinate where flick begins (in pixels or relative units)
|
||||
* `startY` (optional, default `0.5`): y coordinate where flick begins (in pixels or relative units)
|
||||
* `endX` (required): x coordinate where flick ends (in pixels or relative units)
|
||||
* `endY` (required): y coordinate where flick ends (in pixels or relative units)
|
||||
* `element` (optional): ID of element to scope this command to
|
||||
* `POST session:/sessionId/touch/swipe` - perform a swipe/drag on the screen or an element
|
||||
* URL Parameter: sessionId of session to route to
|
||||
* JSON parameters:
|
||||
* `touchCount` (optional, default `1`): how many fingers to flick with
|
||||
* `startX` (optional, default `0.5`): x coordinate where swipe begins (in pixels or relative units)
|
||||
* `startY` (optional, default `0.5`): y coordinate where swipe begins (in pixels or relative units)
|
||||
* `endX` (required): x coordinate where swipe ends (in pixels or relative units)
|
||||
* `endY` (required): y coordinate where swipe ends (in pixels or relative units)
|
||||
* `duration` (optional, default `0.8`): time (in seconds) to spend performing the swipe/drag
|
||||
* `element` (optional): ID of element to scope this command to
|
||||
|
||||
**Note on setting orientation:** Setting the orientation takes different
|
||||
parameters than the tap, flick, and swipe methods. This action is performed
|
||||
by setting the orientation of the browser to "LANDSCAPE" or "PORTRAIT". The
|
||||
alternative access method below does not apply to setting orientation.
|
||||
|
||||
* `POST /session/:sessionId/orientation` - set the orientation of the browser
|
||||
* URL Parameter: sessionId of session to route to
|
||||
* JSON parameters:
|
||||
* `orientation` (required): new orientation, either "LANDSCAPE" or "PORTRAIT"
|
||||
|
||||
## Alternative access method
|
||||
|
||||
Extending the JSON Wire Protocol is great, but it means that the various
|
||||
WebDriver language bindings will have to implement access to these endpoints
|
||||
in their own way. Naturally, this will take different amounts of time
|
||||
depending on the project. We have instituted a way to get around this delay,
|
||||
by using `driver.execute()` with special parameters.
|
||||
|
||||
`POST session/:sessionId/execute` takes two JSON parameters:
|
||||
* `script` (usually a snippet of javascript)
|
||||
* `args` (usually an array of arguments passed to that snippet in the javascript engine)
|
||||
|
||||
In the case of these new mobile methods, `script` must be one of:
|
||||
* `mobile: tap`
|
||||
* `mobile: flick`
|
||||
* `mobile: swipe`
|
||||
* `mobile: scrollTo`
|
||||
* `mobile: scroll`
|
||||
* `mobile: shake`
|
||||
(The `mobile:` prefix allows us to route these requests to the appropriate
|
||||
endpoint).
|
||||
|
||||
And `args` will be an array with one element: a Javascript object defining
|
||||
the parameters for the corresponding function. So, let's say I want to call
|
||||
`tap` on a certain screen position. I can do so by calling `driver.execute`
|
||||
with these JSON parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"script": "mobile: tap",
|
||||
"args": [{
|
||||
"x": 0.8,
|
||||
"y": 0.4
|
||||
}]
|
||||
}
|
||||
```
|
||||
In this example, our new `tap` method will be called with the `x` and `y`
|
||||
params as described above.
|
||||
|
||||
## Code examples
|
||||
|
||||
In these examples, note that the element parameter is always optional.
|
||||
|
||||
## Tap
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```js
|
||||
driver.elementsByTagName('tableCell', function(err, els) {
|
||||
var tapOpts = {
|
||||
x: 150 // in pixels from left
|
||||
, y: 30 // in pixels from top
|
||||
, element: els[4].value // the id of the element we want to tap
|
||||
};
|
||||
driver.execute("mobile: tap", [tapOpts], function(err) {
|
||||
// continue testing
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
* **Java:**
|
||||
|
||||
```java
|
||||
WebElement row = driver.findElements(By.tagName("tableCell")).get(4);
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, Double> tapObject = new HashMap<String, Double>();
|
||||
tapObject.put("x", 150); // in pixels from left
|
||||
tapObject.put("y", 30); // in pixels from top
|
||||
tapObject.put("element", ((RemoteWebElement) row).getId()); // the id of the element we want to tap
|
||||
js.executeScript("mobile: tap", tapObject);
|
||||
```
|
||||
|
||||
```java
|
||||
//In iOS app, if UI element visbile property is "false".
|
||||
//Using element location tap on it.
|
||||
WebElement element = wd.findElement(By.xpath("//window[1]/scrollview[1]/image[1]"));
|
||||
JavascriptExecutor js = (JavascriptExecutor) wd;
|
||||
HashMap<String, Double> tapObject = new HashMap<String, Double>();
|
||||
tapObject.put("x", (double) element.getLocation().getX());
|
||||
tapObject.put("y", (double) element.getLocation().getY());
|
||||
tapObject.put("duration", 0.1);
|
||||
js.executeScript("mobile: tap", tapObject);
|
||||
```
|
||||
|
||||
* **Python:**
|
||||
|
||||
```python
|
||||
driver.execute_script("mobile: tap", {"touchCount":"1", "x":"0.9", "y":"0.8", "element":element.id})
|
||||
```
|
||||
|
||||
* **Ruby:**
|
||||
|
||||
```ruby
|
||||
@driver.execute_script 'mobile: tap', :x => 150, :y => 30
|
||||
```
|
||||
|
||||
* **Ruby:**
|
||||
|
||||
```ruby
|
||||
b = @driver.find_element :name, 'Sign In'
|
||||
@driver.execute_script 'mobile: tap', :element => b.ref
|
||||
```
|
||||
|
||||
* **C#:**
|
||||
|
||||
```c#
|
||||
Dictionary<String, Double> coords = new Dictionary<string, double>();
|
||||
coords.Add("x", 12);
|
||||
coords.Add("y", 12);
|
||||
driver.ExecuteScript("mobile: tap", coords);
|
||||
```
|
||||
|
||||
## Flick
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```js
|
||||
// options for a 2-finger flick from the center of the screen to the top left
|
||||
var flickOpts = {
|
||||
endX: 0
|
||||
, endY: 0
|
||||
, touchCount: 2
|
||||
};
|
||||
driver.execute("mobile: flick", [flickOpts], function(err) {
|
||||
// continue testing
|
||||
});
|
||||
```
|
||||
|
||||
* **Java:**
|
||||
|
||||
```java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, Double> flickObject = new HashMap<String, Double>();
|
||||
flickObject.put("endX", 0);
|
||||
flickObject.put("endY", 0);
|
||||
flickObject.put("touchCount", 2);
|
||||
js.executeScript("mobile: flick", flickObject);
|
||||
```
|
||||
|
||||
## Swipe
|
||||
|
||||
*Note*: Swiping is unfortunately broken in iOS7, because of a bug in Apple's
|
||||
frameworks. For iOS7, see `mobile: scroll` as a workaround that works for most
|
||||
cases.
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```js
|
||||
// options for a slow swipe from the right edge of the screen to the left
|
||||
var swipeOpts = {
|
||||
startX: 0.95
|
||||
, startY: 0.5
|
||||
, endX: 0.05
|
||||
, endY: 0.5
|
||||
, duration: 1.8
|
||||
};
|
||||
driver.execute("mobile: swipe", [swipeOpts], function(err) {
|
||||
// continue testing
|
||||
});
|
||||
```
|
||||
|
||||
* **Java:**
|
||||
|
||||
```java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, Double> swipeObject = new HashMap<String, Double>();
|
||||
swipeObject.put("startX", 0.95);
|
||||
swipeObject.put("startY", 0.5);
|
||||
swipeObject.put("endX", 0.05);
|
||||
swipeObject.put("endY", 0.5);
|
||||
swipeObject.put("duration", 1.8);
|
||||
js.executeScript("mobile: swipe", swipeObject);
|
||||
```
|
||||
|
||||
## Scroll
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```js
|
||||
// scroll the view down
|
||||
driver.execute("mobile: scroll", [{direction: 'down'}], function(err) {
|
||||
// continue testing
|
||||
});
|
||||
```
|
||||
|
||||
* **Java:**
|
||||
|
||||
```java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
HashMap<String, String> scrollObject = new HashMap<String, String>();
|
||||
scrollObject.put("direction", "down");
|
||||
scrollObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: scroll", scrollObject);
|
||||
```
|
||||
|
||||
## Slider
|
||||
|
||||
**iOS**
|
||||
|
||||
* **Java**
|
||||
|
||||
```java
|
||||
// slider values can be string representations of numbers between 0 and 1
|
||||
// e.g., "0.1" is 10%, "1.0" is 100%
|
||||
WebElement slider = wd.findElement(By.xpath("//window[1]/slider[1]"));
|
||||
slider.sendKeys("0.1");
|
||||
```
|
||||
|
||||
**Android**
|
||||
|
||||
The best way to interact with the slider on Android is with the 'mobile:
|
||||
tap' gesture. It is difficult to find a reliable way to set a specific
|
||||
percentage that works on all screen sizes, however. Therefore,
|
||||
it is recommended to write tests that focus on minimum, 50%, and maximum.
|
||||
|
||||
* **Ruby**
|
||||
|
||||
```ruby
|
||||
# 0%
|
||||
@driver.execute_script 'mobile: tap', :x =>slider.location.x, :y =>slider.location.y
|
||||
|
||||
# 100%
|
||||
@driver.execute_script 'mobile: tap', :x =>slider.location.x + slider.size.width - 1, :y =>slider.location.y
|
||||
|
||||
# 50%
|
||||
slider.click
|
||||
```
|
||||
## Set orientation
|
||||
|
||||
* **WD.js:**
|
||||
|
||||
```js
|
||||
driver.setOrientation("LANDSCAPE", function(err) {
|
||||
// continue testing
|
||||
});
|
||||
```
|
||||
|
||||
* **Python:**
|
||||
|
||||
```python
|
||||
driver.orientation = "LANDSCAPE"
|
||||
```
|
||||
|
||||
## Scroll To
|
||||
|
||||
```ruby
|
||||
b = @driver.find_element :name, 'Sign In'
|
||||
@driver.execute_script 'mobile: scrollTo', :element => b.ref
|
||||
```
|
||||
|
||||
```java
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
WebElement element = wd.findElement(By.name("Log In"));;
|
||||
HashMap<String, String> scrollToObject = new HashMap<String, String>();
|
||||
scrollToObject.put("element",((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: scrollTo", scrollToObject);
|
||||
```
|
||||
|
||||
## longTap
|
||||
|
||||
* **c#**
|
||||
|
||||
```c#
|
||||
// long tap an element
|
||||
//
|
||||
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
parameters.Add("using", _attributeType);
|
||||
parameters.Add("value", _attribute);
|
||||
Response response = rm.executescript(DriverCommand.FindElement, parameters);
|
||||
Dictionary<string, object> elementDictionary = response.Value as Dictionary<string, object>;
|
||||
string id = null;
|
||||
if (elementDictionary != null)
|
||||
{
|
||||
id = (string)elementDictionary["ELEMENT"];
|
||||
}
|
||||
IJavaScriptExecutor js = (IJavaScriptExecutor)remoteDriver;
|
||||
Dictionary<String, String> longTapObject = new Dictionary<String, String>();
|
||||
longTapObject.Add("element", id);
|
||||
js.ExecuteScript("mobile: longClick", longTapObject);
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
# Cross platform mobile methods
|
||||
|
||||
## Reset
|
||||
|
||||
Mobile reset will reset the app's state.
|
||||
|
||||
Ruby + [appium_lib gem](https://github.com/appium/ruby_lib)
|
||||
|
||||
```ruby
|
||||
mobile :reset
|
||||
```
|
||||
|
||||
Ruby without the gem
|
||||
|
||||
```ruby
|
||||
@driver.execute_script 'mobile: reset'
|
||||
```
|
||||
|
||||
## pullFile
|
||||
|
||||
Fetch a file from the device's filesystem, returning it base64 encoded.
|
||||
|
||||
Takes a single argument, `path`. On Android and iOS, this is either the path
|
||||
to the file (relative to the root of the app's file system). On iOS only,
|
||||
if path starts with `/AppName.app`, which will be replaced with the
|
||||
application's .app directory
|
||||
|
||||
```ruby
|
||||
# Android and iOS
|
||||
@driver.execute_script 'mobile: pullFile', {path: '/Library/AddressBook/AddressBook.sqlitedb'} #=> /Library/AddressBook/AddressBook.sqlitedb
|
||||
|
||||
# iOS only
|
||||
@driver.execute_script 'mobile: pullFile, {path: '/UICatalog.app/logfile.log'} #=> /Applications/12323-452262-24241-23-124124/UICatalog.app/logfile.log
|
||||
```
|
||||
|
||||
Ruby
|
||||
|
||||
```ruby
|
||||
@driver.execute_script('mobile: pullFile', {path: '/Library/AddressBook/AddressBook.sqlitedb'})
|
||||
```
|
||||
|
||||
## Android mobile methods
|
||||
|
||||
## KeyEvent
|
||||
|
||||
[KeyEvent](http://developer.android.com/reference/android/view/KeyEvent.html) enables sending a keycode to Android.
|
||||
|
||||
Press the system menu button in Java.
|
||||
|
||||
```java
|
||||
HashMap<String, Integer> keycode = new HashMap<String, Integer>();
|
||||
keycode.put("keycode", 82);
|
||||
((JavascriptExecutor)driver).executeScript("mobile: keyevent", keycode);
|
||||
```
|
||||
|
||||
Ruby + [appium_lib gem](https://github.com/appium/ruby_lib)
|
||||
|
||||
```ruby
|
||||
mobile :keyevent, keycode: 82
|
||||
```
|
||||
|
||||
Ruby without the gem
|
||||
|
||||
```ruby
|
||||
@driver.execute_script 'mobile: keyevent', :keycode => 82
|
||||
```
|
||||
|
||||
## Mobile find
|
||||
|
||||
Java
|
||||
|
||||
See [MobileFindJavaTest.java](/sample-code/examples/java/junit/src/test/java/com/saucelabs/appium/MobileFindJavaTest.java)
|
||||
|
||||
Ruby + [appium_lib gem](https://github.com/appium/ruby_lib)
|
||||
|
||||
```ruby
|
||||
scroll_to 'Gallery'
|
||||
```
|
||||
@@ -1,39 +0,0 @@
|
||||
# Touch Actions
|
||||
|
||||
WebDriver provides an API to send some kinds of touch gestures to the devices,
|
||||
for example, to long press an element you can do:
|
||||
|
||||
For iOS Application:
|
||||
|
||||
```java
|
||||
final WebElement imageView = searchResults.findElement(By.tagName("ImageView"));
|
||||
new TouchActions(driver).longPress(imageView).perform();
|
||||
```
|
||||
|
||||
For Android Application:
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
WebElement element = wd.findElement(By.name("API Demo"));
|
||||
JavascriptExecutor js = (JavascriptExecutor) wd;
|
||||
HashMap<String, String> tapObject = new HashMap<String, String>();
|
||||
tapObject.put("element", ((RemoteWebElement) element).getId());
|
||||
js.executeScript("mobile: longClick", tapObject);
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
```python
|
||||
element = wd.find_element_by_xpath("your_element_xpath")
|
||||
wd.execute_script("mobile: longClick",{ "touchCount": 1, "x": 0, "y": 300, "element":element.id })
|
||||
```
|
||||
|
||||
Currently Appium support some of the gestures in the Touch Actions API:
|
||||
|
||||
* flick
|
||||
* long press
|
||||
* single tap
|
||||
|
||||
Some other gestures are supported through the "Alternative access method"
|
||||
explained in [Automating mobile gestures](gestures.md)
|
||||
Reference in New Issue
Block a user