appium-client

Rust client for Appium Server, for automated mobile app testing. It is based on fantoccini.

To learn more about Appium-specific features implemented here, see the documentation. Below are examples that will help you quickly learn how to use key features.

Also check out the examples.

Sample usage

Creating the client

Create Appium client that will be used to issue commands and locate elements.

A client is an object that manages the connection to Appium server and issues commands to it. Thus, we need capabilities that describe the automation environment and the server URL to create a client.

You can read more about capabilities in Appium's docs.

```rust use appiumclient::ClientBuilder; use appiumclient::capabilities::*;

[tokio::main]

async fn main() -> Result<(), Box> { let mut capabilities = AndroidCapabilities::new(); capabilities.udid("emulator-5554"); capabilities.app("/apps/sample.apk"); capabilities.appwaitactivity("com.example.AppActivity");

let client = ClientBuilder::native()
    .capabilities(capabilities.into())
    .connect("http://localhost:4723/wd/hub/")
    .await?;

Ok(())

} ```

Finding an element on screen

Locate an element by using your favorite location strategy (eg. by UiAutomator 2).

Other strategies, like name, XPath, iOS Class Chain etc. are also supported.

```rust // you need this to use Appium locators with fantoccini's Client use appium_client::find::{AppiumFind, By};

let element = client .findby(By::accessibilityid("Click this")) .await?;

element.click().await?; ```

Waiting for an element to appear

You can wait for element if it does not appear immediately on screen.

The wait, by default, is 30 seconds. During the wait, the client performs a search every 250 ms until the element finally appears, or it hits the timeout.

```rust // you need these to use Appium-enhanced wait with fantoccini's Client use appiumclient::find::{AppiumFind, By}; use appiumclient::wait::AppiumWait;

let element = client .appiumwait() .forelement(By::uiautomator("new UiSelector().className(\"android.widget.ImageView\");")) .await?;

element.click().await?; ```

Limiting the wait

You can define how long to wait for the element and how often to check if it's already appeared.

This is useful in situations when you know something should appear sooner. And if it doesn't, then something else happened, and you don't want to bother waiting full 30 seconds until timeout.

The search interval may be also too adjusted so that the Appium server has more time to breathe.

```rust // you need these to use Appium-enhanced wait with fantoccini's Client use appiumclient::find::{AppiumFind, By}; use appiumclient::wait::AppiumWait;

let element = client .appiumwait() .atmost(Duration::fromsecs(20)) .checkevery(Duration::frommillis(500)) .forelement(By::uiautomator("new UiSelector().className(\"android.widget.ImageView\");")) .await?;

element.click().await?; ```

Locating many elements

To locate multiple elements, use find_all_by or .appium_wait().for_elements(..).

The first method works just like find_by - it yields results immediately. The second one just waits given time until at least one element appears. It works like the above example.

```rust // you need these to use Appium-enhanced wait with fantoccini's Client use appiumclient::find::{AppiumFind, By}; use appiumclient::wait::AppiumWait;

let result = client .appiumwait() .forelements(By::class_name("android.widget.LinearLayout")) .await?;

result.first().unwrap().click().await?; ```

Nested search

You can also perform search inside elements you found.

It is useful in cases when you want to find the parent element first, and then find a specific child inside. No matter how bizarre that sounds, it is a useful feature when working with DOM.

```rust // you need this to use Appium locators with fantoccini's Client use appium_client::find::{AppiumFind, By};

let element = client .findby(By::accessibilityid("Click this")) .await?;

// now let's find a child of element let imagechild = element .findby(By::class_name("android.widget.ImageButton")) .await?; ```

Scrolling

To scroll, you can use touch actions. For example, let's scroll up by simulating a swipe.

Remember that the swipe will "pull" the screen, so you need to swipe down to "pull" the screen down, revealing top content.

```rust let swipedown = TouchActions::new("finger".tostring()) // position the finger first .then(PointerAction::MoveTo { duration: Some(Duration::frommillis(0)), x, y }) // THEN touch the screen .then(PointerAction::Down { button: MOUSEBUTTONLEFT // believe me, it is not a mouse, but a simple touch }) // THEN move the finger through the screen .then(PointerAction::MoveTo { duration: Some(Duration::frommillis(500)), x, y });

client.perform_actions(swipe_down)
    .await?;

```

See basic example here.