9

I am getting below error with new TouchActions class.

  • JDK version: 1.8
  • Appium: 1.7.2
  • appium.java-client.version: 6.0.0-BETA2
  • selenium.java.version: 3.8.1

 

TouchActions actions = new TouchActions(appiumDriver);

Runtime Error:

java.lang.ClassCastException: io.appium.java_client.ios.IOSDriver cannot be cast to org.openqa.selenium.interactions.HasTouchScreen

Whereas, old below works all fine:

TouchAction touchAction = new TouchAction(appiumDriver);
James Z
  • 12,209
  • 10
  • 24
  • 44
user2451016
  • 1,857
  • 3
  • 20
  • 44

4 Answers4

2

This is still an issue in appium, apparently. Right now, the only way to do it in native Android is by an adb command:

adb shell input touchscreen swipe <x> <y> <x> <y> <durationMs>

In Java you can implement this using the following code:

    public static String swipe(int startx, int starty, int endx, int endy, int duration) {
        return executeAsString("adb shell input touchscreen swipe "+startx+" "+starty+" "+endx+" "+endy+" "+duration);
    }

    private static String executeAsString(String command) {
        try {
            Process pr = execute(command);
            BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = input.readLine()) != null) {
                if (!line.isEmpty()) {
                    sb.append(line);
                }
            }
            input.close();
            pr.destroy();
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException("Execution error while executing command" + command, e);
        }
    }    

    private static Process execute(String command) throws IOException, InterruptedException {
        List<String> commandP = new ArrayList<>();
        String[] com = command.split(" ");
        for (int i = 0; i < com.length; i++) {
            commandP.add(com[i]);
        }
        ProcessBuilder prb = new ProcessBuilder(commandP);
        Process pr = prb.start();
        pr.waitFor(10, TimeUnit.SECONDS);
        return pr;
    }

However, if you are using an app that has a webview you can better use JavaScript to scroll. The code to scroll down is:

((JavascriptExecutor)driver).executeScript("window.scrollBy(0,500)", "");

Or to scroll up:

((JavascriptExecutor)driver).executeScript("window.scrollBy(0,-500)", "");

Or to scroll to a certain element:

((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);

Be sure to switch to the webview context before using this.

Simon Baars
  • 1,877
  • 21
  • 38
  • Thanks for elaborating this. But could you please advise how to achieive this for iOS / iOS Cordova WebView? Thanks – user2451016 Apr 23 '18 at 08:41
  • In webview you should be able to use JavaScript: `((JavascriptExecutor)driver).executeScript("window.scrollBy(0,500)", "");`. Please report if it works. – Simon Baars Apr 23 '18 at 11:29
  • Yes. window.scrollTo() and window.scrollBy() methods are working. But I need to scroll till certain element, instead of scrolling by a fixed length. – user2451016 Apr 23 '18 at 14:06
  • 1
    The following should scroll to an element: `((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);`. You might need to wait around 250ms for the element to actually scroll into view (`Thread.sleep(250);`). – Simon Baars Apr 24 '18 at 06:27
1

Solution is to use Appium TouchAction instead of Selenium TouchActions.

import io.appium.java_client.TouchAction;

public AndroidDriver<MobileElement> driver = new TouchAction(driver);

public void tap(MobileElement element) {

  getTouchAction()
    .tap(
      new TapOptions().withElement(
        ElementOption.element(
          element)))
    .perform();
}

Call the method ():

tap(myMobileElement);
Zon
  • 18,610
  • 7
  • 91
  • 99
1

Use W3C Actions API to perform gestures.

public void horizontalSwipingTest() throws Exception {
    login();
    driver.findElementByAccessibilityId("slider1").click();
    wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId("slider")));
    MobileElement slider = driver.findElementByAccessibilityId("slider");

    Point source = slider.getLocation();

    PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
    Sequence dragNDrop = new Sequence(finger, 1);
    dragNDrop.addAction(finger.createPointerMove(Duration.ofMillis(0),
            PointerInput.Origin.viewport(), source.x, source.y));
    dragNDrop.addAction(finger.createPointerDown(PointerInput.MouseButton.MIDDLE.asArg()));
    dragNDrop.addAction(new Pause(finger, Duration.ofMillis(600)));
    dragNDrop.addAction(finger.createPointerMove(Duration.ofMillis(600),
            PointerInput.Origin.viewport(),
            source.x + 400, source.y));
    dragNDrop.addAction(finger.createPointerUp(PointerInput.MouseButton.MIDDLE.asArg()));
    driver.perform(Arrays.asList(dragNDrop));
}


public void verticalSwipeTest() throws InterruptedException {
    login();
    wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId("verticalSwipe")));
    driver.findElementByAccessibilityId("verticalSwipe").click();
    wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId("listview")));
    verticalSwipe("listview");
}

private void verticalSwipe(String locator) throws InterruptedException {
    Thread.sleep(3000);
    MobileElement slider = driver.findElementByAccessibilityId(locator);
    Point source = slider.getCenter();
    PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
    Sequence dragNDrop = new Sequence(finger, 1);
    dragNDrop.addAction(finger.createPointerMove(Duration.ofMillis(0),
            PointerInput.Origin.viewport(),
            source.x / 2, source.y + 400));
    dragNDrop.addAction(finger.createPointerDown(PointerInput.MouseButton.MIDDLE.asArg()));
    dragNDrop.addAction(finger.createPointerMove(Duration.ofMillis(600),
            PointerInput.Origin.viewport(), source.getX() / 2, source.y / 2));
    dragNDrop.addAction(finger.createPointerUp(PointerInput.MouseButton.MIDDLE.asArg()));
    driver.perform(Arrays.asList(dragNDrop));
}

Examples of other gestures can be found here: https://github.com/saikrishna321/VodQaAdvancedAppium/blob/master/src/test/java/com/appium/gesture/GestureTest.java

Documentation is available at: https://appiumpro.com/editions/29

Appu Mistri
  • 768
  • 8
  • 26
1

Use io.appium.java_client.TouchAction class.

Step 1

TouchAction action = new TouchAction(driver);

Here driver is an instance of AppiumDriver.

Step 2

WebElement ele = driver.findElement(By.id("locator"));

action.tap(new TapOptions().withElement(new ElementOption().withElement(ele))).perform();

With the new implementation of TouchAction you cannot directly pass weblement.

dependency used

<dependency>
        <groupId>io.appium</groupId>
        <artifactId>java-client</artifactId>
        <version>7.0.0</version>
    </dependency>
Community
  • 1
  • 1