Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassCastException with new Appium-java TouchActions

Tags:

appium

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);
like image 725
user2451016 Avatar asked Jan 26 '18 09:01

user2451016


3 Answers

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.

like image 79
Simon Baars Avatar answered Nov 16 '22 20:11

Simon Baars


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

like image 32
Appu Mistri Avatar answered Nov 16 '22 20:11

Appu Mistri


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);
like image 1
Zon Avatar answered Nov 16 '22 21:11

Zon