microsoft / WinAppDriver

Windows Application Driver
MIT License
3.7k stars 1.41k forks source link

Winappdriver (C#): Click()/Doubleclick() is not working with action class after MoveByOffset with TScon utilty cmd #1940

Open Swetha-Boddu opened 1 year ago

Swetha-Boddu commented 1 year ago

Hi,

I am executing below command from ADO pipeline to run cases in VM in locked(local PC) mode.

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$sessionid=((quser $env:USERNAME | select -Skip 1) -split '\s+')[2]; tscon $sessionid /dest:console" 2> UnlockErrors.log

VM gets disconnected and 70%cases are passing. Whereas 30 % cases are failing because when we select source element and paste into flowsheet , it is navigating properly to the selected co-ordinates but the click is not happening, hence it is failing.

Can you please verify below code lines and suggest if any solution.

        Appsession.FindElementByXPath("//Button[@Name=\"Source\"]").Click();

//(I wanted to paste source element on flowsheet at particular x y co-ordinates (659, 241))

  Actions act1 = new Actions(Appsession);
        act1.MoveToElement(Appsession.FindElementByXPath("//Pane[@ClassName=\"AfxFrameOrView140\"]"), 0, 0).MoveByOffset(659, 241).Click().Build().Perform();

//(Whereas without action class the click is working fine on same flowsheet as shown below.) Appsession.FindElementByXPath("//Pane[@ClassName=\"AfxFrameOrView140\"]").Click(); But i wanted to click at given x, y co-ordinates.

Note: The above code is absolutely working fine in interactive mode.

Thanks, Swetha

anunay1 commented 1 year ago

Then use it without action.

RakeshDangi-slt commented 11 months ago

You cannot use actions to perform clicks directly using appium, you have to use a work around of this kind to perform actions: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));
}

}