WinAppDriver icon indicating copy to clipboard operation
WinAppDriver copied to clipboard

Appium windows driver not supporting Actions?

Open Klarahov opened this issue 2 years ago • 2 comments

When I run my Windows app test with WinAppDriver in the background, they all run green. However, when instead using the appium windows driver (which we will have to use in the future if using the 5.x appium webdriver), my tests fail when using Actions.

Code: var actions = new Actions(Driver); actions.MoveByOffset(30, 0).Click().Perform();

--> "Currently only pen and touch pointer input source types are supported error"

I've seen this error in other threads, but nothing that could solve it. Is the solution to just not use the appium windows driver and then to never upgrade to appium webdriver 5.x, or is there a workaround .. ?

Klarahov avatar Oct 25 '23 12:10 Klarahov

yes there is a Work Around to this, as actions has been deprecated and you cant you them anymore, here is how I am using them: package com.desktop.automation.utils;

import java.io.IOException; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.stream.Collectors;

import org.openqa.selenium.Keys; import org.openqa.selenium.remote.RemoteWebElement;

import com.desktop.automation.constant.Constant.DesktopParamKeyName;

import io.appium.java_client.windows.WindowsDriver; import lombok.extern.log4j.Log4j2;

@Log4j2 public class AppiumWokaround {

private static AppiumWokaround appiumWokaround;

public static AppiumWokaround getInstance() {
    if (appiumWokaround == null) {
        appiumWokaround = new AppiumWokaround();
    }
    return appiumWokaround;
}


public static void launchApplicationDirectly(String appPath) {
    // Include 'automationName' and 'platformName' in the capabilities
    String jsonCapabilities = String.format(
        "{\"capabilities\": {\"alwaysMatch\": {\"app\": \"%s\", \"appium:automationName\": \"Windows\", \"platformName\": \"Windows\"}}}", 
        URLEncoder.encode(appPath, StandardCharsets.UTF_8)
    );

    String newSessionUrl = DesktopParamKeyName.WIN_APP_DRIVER_URL + "/session";

    HttpClient httpClient = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(newSessionUrl))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(jsonCapabilities))
            .build();

    try {
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        log.info("Response status code: {}", response.statusCode());
        log.info("Response body: {}", response.body());
    } catch (Exception e) {
        log.error("Error sending request to Appium server: " + e.getMessage(), e);
    }
}


private enum ActionType {
    CLICK, DOUBLE_CLICK, BUTTON_DOWN, BUTTON_UP
}

private String getUri(WindowsDriver driver, String action) {    	
	return String.format(
        "%s/session/%s/%s",
        DesktopParamKeyName.WIN_APP_DRIVER_URL,
        driver.getSessionId().toString(),
        action
    );
}

private void performActionOnElement(WindowsDriver driver, RemoteWebElement element, ActionType action) {
    this.moveToElement(driver, element);
    switch (action) {
        case CLICK:
            callRest(getUri(driver, "click"), HttpRequest.BodyPublishers.noBody());
            break;
        case DOUBLE_CLICK:
            callRest(getUri(driver, "doubleclick"), HttpRequest.BodyPublishers.noBody());
            break;
        case BUTTON_DOWN:
            callRest(getUri(driver, "buttondown"), HttpRequest.BodyPublishers.noBody());
            break;
        case BUTTON_UP:
            callRest(getUri(driver, "buttonup"), HttpRequest.BodyPublishers.noBody());
            break;
    }
}

public void moveToElement(WindowsDriver driver, RemoteWebElement element) {
    String uri = getUri(driver, "moveto");
    String json = String.format("{\"element\":\"%s\"}", element.getId());
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void moveToElement(WindowsDriver driver, RemoteWebElement element,int x, int y) {
	moveToElement(driver,element);
	String uri = getUri(driver, "moveto");
    String json = String.format("{\"xoffset\":%d,\"yoffset\":%d}", x, y);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void contextClick(WindowsDriver driver, RemoteWebElement element) {
    this.moveToElement(driver, element);
    String uri = getUri(driver, "click");
    String json = String.format("{\"button\":2}");
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void contextClick(WindowsDriver driver) {
    String uri = getUri(driver, "click");
    String json = String.format("{\"button\":2}");
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void contextClick(WindowsDriver driver, RemoteWebElement element, int x, int y) {
    // Move to the specified coordinates relative to the top-left corner of the element
	this.moveToElementWithOffset(driver,element, x, y);

    // Perform the right-click
    String uri = getUri(driver, "click");
    String json = String.format("{\"button\":2}");
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void doubleClick(WindowsDriver driver, RemoteWebElement element) {
    performActionOnElement(driver, element, ActionType.DOUBLE_CLICK);
}

public void doubleClickAtCurrentLocation(WindowsDriver driver) {
    String uri = getUri(driver, "doubleclick");
    callRest(uri, HttpRequest.BodyPublishers.noBody());
}


public void click(WindowsDriver driver, RemoteWebElement elementToClick) {
    performActionOnElement(driver, elementToClick, ActionType.CLICK);
}

public void moveToElementAndSendKeys(WindowsDriver driver, RemoteWebElement element, String keyToSend) {
    this.moveToElement(driver, element);
    String uri = getUri(driver, "keys");
    String json = String.format("{\"value\":[\"%s\"]}", keyToSend);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void moveToElementAndClick(WindowsDriver driver, RemoteWebElement element) {
    this.moveToElement(driver, element);
    performActionOnElement(driver, element, ActionType.CLICK);
}

public void clickWithoutElement(WindowsDriver driver) {
    String uri = getUri(driver, "click");
    callRest(uri, HttpRequest.BodyPublishers.noBody());
}

public void sendKeysWithoutElement(WindowsDriver driver, String text) {
    String uri = getUri(driver, "keys");
    String json = String.format("{\"value\":[\"%s\"]}", text);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void moveToElementWithOffsetAndClick(WindowsDriver driver, RemoteWebElement element, int xCoordinates, int yCoordinates) {
    this.moveToElementWithOffset(driver,element, xCoordinates, yCoordinates);
    clickWithoutElement(driver);
}

public void moveToElementWithOffset(WindowsDriver driver, RemoteWebElement element, int xCoordinates, int yCoordinates) {
    this.moveToElement(driver, element);
    moveByOffset(driver, xCoordinates, yCoordinates);
}

public void clickAndHoldAndMoveToElement(WindowsDriver driver, RemoteWebElement sourceElement, RemoteWebElement destinationElement) {
    performActionOnElement(driver, sourceElement, ActionType.BUTTON_DOWN);
    this.moveToElement(driver, destinationElement);
}

public void dragAndDrop(WindowsDriver driver, RemoteWebElement dragElement, RemoteWebElement dropElement) {
    clickAndHoldAndMoveToElement(driver, dragElement, dropElement);
    performActionOnElement(driver, dropElement, ActionType.BUTTON_UP);
}

public void dragAndDropBy(WindowsDriver driver, RemoteWebElement element, int xcords, int ycords) {
    performActionOnElement(driver, element, ActionType.BUTTON_DOWN);
    moveByOffset(driver, xcords, ycords);
    performActionOnElement(driver, element, ActionType.BUTTON_UP);
}

public void moveByOffset(WindowsDriver driver, int xCoordinates, int yCoordinates) {
    String uri = getUri(driver, "moveto");
    String json = String.format("{\"xoffset\":%d,\"yoffset\":%d}", xCoordinates, yCoordinates);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}


public void moveByOffsetAndClick(WindowsDriver driver, int xCoordinates, int yCoordinates) {
    moveByOffset(driver, xCoordinates, yCoordinates);
    clickWithoutElement(driver);
}

public void release(WindowsDriver driver, RemoteWebElement element) {
    performActionOnElement(driver, element, ActionType.BUTTON_UP);
}

public void clickAndHold(WindowsDriver driver, RemoteWebElement element) {
    performActionOnElement(driver, element, ActionType.BUTTON_DOWN);
}


private static void callRest(String uri, HttpRequest.BodyPublisher body) {
    log.info("URI: {}", uri);
    //log.info("body: {}", body.toString());
    HttpClient httpClient = HttpClient.newHttpClient();

    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(uri))
            .header("Content-Type", "application/json")
            .POST(body)
            .build();

    try {
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        log.info("RETURN status code: {}", response.statusCode());
        //log.info("RETURN: {}", response.body());
    } catch (IOException e) {
        log.error("IO Exception during HTTP call", e);
        throw new RuntimeException(e);
    } catch (InterruptedException e) {
        log.error("Interrupted Exception during HTTP call", e);
        Thread.currentThread().interrupt();  // Preserve the interrupt status
        throw new RuntimeException(e);
    }
}

public void sendKeysWithoutElement(WindowsDriver driver, Keys keyToSend) {
    sendKeysWithoutElement(driver, keyToSend.toString());
}

public void pressKeysSimultaneously(WindowsDriver driver, String[] keys) {
    // Convert the String array to a JSON array representation
    String jsonKeysArray = Arrays.stream(keys)
            .map(key -> "\"" + key + "\"")
            .collect(Collectors.joining(",", "[", "]"));

    String uri = getUri(driver, "keys");
    String json = String.format("{\"value\":%s}", jsonKeysArray);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void holdKey(WindowsDriver driver, String key) {
    // This will simulate a key down action
    String uri = getUri(driver, "keydown");
    String json = String.format("{\"value\":[\"%s\"]}", key);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

public void releaseKey(WindowsDriver driver, String key) {
    // This will simulate a key up action
    String uri = getUri(driver, "keyup");
    String json = String.format("{\"value\":[\"%s\"]}", key);
    callRest(uri, HttpRequest.BodyPublishers.ofString(json));
}

} Hope this helps.

RakeshDangi-slt avatar Dec 27 '23 12:12 RakeshDangi-slt

Thanks for replying :)

Klarahov avatar Jan 03 '24 11:01 Klarahov