microsoft / WinAppDriver

Windows Application Driver
MIT License
3.69k stars 1.4k forks source link

how to switch application winappdriver in java #886

Open YeonwooJeong opened 5 years ago

YeonwooJeong commented 5 years ago

I want to switch File Explorer and Chrome browser.

how to switch application?

in my code

@BeforeClass public static void setup() { try { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("app", "C:\Windows\explorer.exe"); ExplorerSession = new WindowsDriver(new URL("http://127.0.0.1:4723"), capabilities); ExplorerSession.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS); actions = new Actions(ExplorerSession); modules = new Modules(ExplorerSession);} can I generate new Session?

I reference next link

https://github.com/Microsoft/WinAppDriver/tree/v1.0#creating-a-desktop-session https://github.com/microsoft/WinAppDriver/blob/35a659232060a6e436cbb8393ae9a09bab12bc89/Samples/C%23/StickyNotesTest/StickyNotesSession.cs

but I could't resolve this problem

Not enough information in Java.

No API documents found, either.

where is example for java?

DoreenG commented 5 years ago

You can set capabilities.setCapability("app", "Root"); and then open the Chrome Browser with Selenium. As far as I know from my own experience you can only have one session with the WinAppDriver at a time.

YeonwooJeong commented 5 years ago

You can set capabilities.setCapability("app", "Root"); and then open the Chrome Browser with Selenium. As far as I know from my own experience you can only have one session with the WinAppDriver at a time.

Thanks for your answer. So according to your answer, Can't I come and go to two different applications in winappdriver?

ex) StickyNote <-> Notepad

DoreenG commented 5 years ago

If you set root you can control your whole screen. I did my bachelor thesis with WinAppDriver and controlled two softphone clients in this way. You can with UIRecorder you can find out XPath from applications by manual click. This application also generated code but in C#. With the class Actions.class you can try some key combinations.

YeonwooJeong commented 5 years ago

If you set root you can control your whole screen. I did my bachelor thesis with WinAppDriver and controlled two softphone clients in this way. You can with UIRecorder you can find out XPath from applications by manual click. This application also generated code but in C#. With the class Actions.class you can try some key combinations.

If you used two soft phone clients, did you create three sessions: root, soft phone 1, soft phone 2?

I don't know this way.. root set is..

DesiredCapabilities desktopCapabilities = new DesiredCapabilities(); desktopCapabilities.setCapability("app", "Root"); desktopCapabilities.setCapability("deviceName", "WindowsPC"); WindowsDriver desktopSession = new WindowsDriver<>(new URL("http://127.0.0.1:4723"), desktopCapabilities);

DoreenG commented 5 years ago

Only one Session.

DoreenG commented 5 years ago

So I put my driver, because I needed it for my whole suite (TestNG).

*/ @BeforeSuite public static void setup() { try { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("deviceName", "Windows"); capabilities.setCapability("platformVersion", "10"); capabilities.setCapability("app", "Root"); setSession(new WindowsDriver(new URL(PropertyLoader.getUrl()), capabilities)); } catch (Exception e) { LOG.error("Exception: " + e.getMessage() + "," + "Throwable: " + e.getCause()); reporter("Exception: " + e.getMessage() + "," + "Throwable: " + e.getCause()); } getSession().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS); }

YeonwooJeong commented 5 years ago

So I put my driver, because I needed it for my whole suite (TestNG).

*/ @BeforeSuite public static void setup() { try { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("deviceName", "Windows"); capabilities.setCapability("platformVersion", "10"); capabilities.setCapability("app", "Root"); setSession(new WindowsDriver(new URL(PropertyLoader.getUrl()), capabilities)); } catch (Exception e) { LOG.error("Exception: " + e.getMessage() + "," + "Throwable: " + e.getCause()); reporter("Exception: " + e.getMessage() + "," + "Throwable: " + e.getCause()); } getSession().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS); }

Thanks. So How to come and go to two softphone client? Can you take the code as an example?

DoreenG commented 5 years ago

I had both icons pinned to the taskbar and called from there with WinAppDriver and Selenium. Since I did everything with TestNG I defined the test in testng.xml.

Yes, you can.

anniekvandijk commented 5 years ago

I use this in my c# project. I think you can use it likewise in Java

private static WindowsDriver<WindowsElement> GetDesktopSession()
        {
            // Get Desktop Session
            var desktopCapabilities = new AppiumOptions();
            desktopCapabilities.AddAdditionalCapability("app", "Root");
            desktopCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
            var session =  new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), desktopCapabilities);
            return session;
        }

private static WindowsDriver<WindowsElement> Driver1()
        {
            var desktopSession = GetDesktopSession();
            var modal = desktopSession.FindElementByName(screenName1);
            var adasModalWindowHandle = modal.GetAttribute("NativeWindowHandle");
            adasModalWindowHandle = (int.Parse(adasModalWindowHandle)).ToString("x");

            var appModalCapabilities = new AppiumOptions();
            appModalCapabilities.AddAdditionalCapability("appTopLevelWindow", adasModalWindowHandle);
            return new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appModalCapabilities);
        }

private static WindowsDriver<WindowsElement> Driver2()
        {
            var desktopSession = GetDesktopSession();
            var modal = desktopSession.FindElementByName(screenName2);
            var adasModalWindowHandle = modal.GetAttribute("NativeWindowHandle");
            adasModalWindowHandle = (int.Parse(adasModalWindowHandle)).ToString("x");

            var appModalCapabilities = new AppiumOptions();
            appModalCapabilities.AddAdditionalCapability("appTopLevelWindow", adasModalWindowHandle);
            return new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appModalCapabilities);
        }
YeonwooJeong commented 5 years ago

desktopCapabilities.AddAdditionalCapability("deviceName", "WindowsPC

Thanks for your answer. I tried to it but occured error

console error :

User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_91)

{"using":"name","value":"보내기(N)"} HTTP/1.1 200 OK Content-Length: 128 Content-Type: application/json

{"sessionId":"F22340B8-5B38-4E08-A875-DB0F2572E88A","status":0,"value":{"ELEMENT":"42.790882.4.-2147483646.11772.121441403.24"}}

eclipse error : java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to io.appium.java_client.windows.WindowsElement at com.nts.winapp.cloud.Modules.RightClick(Modules.java:45)

this is code :

Sesson.java

public class Session { public static WindowsDriver desktopSession = null;

public static WindowsDriver<WindowsElement> GetDesktopSession()
{
    // Get Desktop Session
     DesiredCapabilities desktopCapabilities = new DesiredCapabilities();
     desktopCapabilities.setCapability("app", "Root");
     desktopCapabilities.setCapability("deviceName", "WindowsPC");
     try {
        desktopSession = new WindowsDriver(new URL("http://127.0.0.1:4723"), desktopCapabilities);
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
     desktopSession.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

    return desktopSession;
}

}

error occured at Line 45

public void RightClick(String name) {       
    WebElement elementLocator = winapp.findElementByName(name);
    actions.contextClick(elementLocator).perform();
    Session.GetDesktopSession().findElementByName("보내기(N)").click(); <-- this Line      
}

this is elements of 보내기(N)

image

anniekvandijk commented 5 years ago

The good news is: you found an element 👍. So you do have a session driver. But it is returned as a RemoteWebElement 😔. I found this issue: https://github.com/microsoft/WinAppDriver/issues/510. Looks like a different problem.

To make sure it’s not your code put your type new WindowsDriver<WindowsElement> In your code.

In C# we have a similar bug. FindElements returns a AppiumWebElement. Workarround is to cast it like this: IList<WindowsElement> list = (IList<WindowsElement>)element.FindElementsByName("name2"); Maybe java has this option too?

YeonwooJeong commented 5 years ago

The good news is: you found an element 👍. So you do have a session driver. But it is returned as a RemoteWebElement 😔. I found this issue: #510. Looks like a different problem.

To make sure it’s not your code put your type new WindowsDriver<WindowsElement> In your code.

In C# we have a similar bug. FindElements returns a AppiumWebElement. Workarround is to cast it like this: IList<WindowsElement> list = (IList<WindowsElement>)element.FindElementsByName("name2"); Maybe java has this option too?

maybe I know

WebElement layout = Session.GetDesktopSession().findElementByClassName("name");

List<WebElement> list = Session.GetDesktopSession().findElementsByClassName("name");

but 보내기(N) have not ClassName (not supported)

YeonwooJeong commented 5 years ago

@timotiusmargo can you help mE?

related issue https://github.com/microsoft/WinAppDriver/issues/896

timotiusmargo commented 5 years ago

Hi @YeonwooJeong,

@anniekvandijk is totally on point. You can totally have as many sessions as you want. This enable you to have two different application interacting to each other in the test device. Practically speaking though, you should have one session per application and one for the desktop when necessary. Your test runner should execute each test in series (sequence) instead of in parallel even if it involves multiple sessions each driving different application.

You are right about the lack of Java example and I hope this will improve over time. But if the following snippet works for you,

WebElement layout = Session.GetDesktopSession().findElementByClassName("name");
List<WebElement> list = Session.GetDesktopSession().findElementsByClassName("name");

then the following should also work

WebElement layout = Session.GetDesktopSession().findElementByName("name");
List<WebElement> list = Session.GetDesktopSession().findElementsByName("name");
YeonwooJeong commented 5 years ago

Hi @YeonwooJeong,

@anniekvandijk is totally on point. You can totally have as many sessions as you want. This enable you to have two different application interacting to each other in the test device. Practically speaking though, you should have one session per application and one for the desktop when necessary. Your test runner should execute each test in series (sequence) instead of in parallel even if it involves multiple sessions each driving different application.

You are right about the lack of Java example and I hope this will improve over time. But if the following snippet works for you,

WebElement layout = Session.GetDesktopSession().findElementByClassName("name");
List<WebElement> list = Session.GetDesktopSession().findElementsByClassName("name");

then the following should also work

WebElement layout = Session.GetDesktopSession().findElementByName("name");
List<WebElement> list = Session.GetDesktopSession().findElementsByName("name");

Why do you use the list? What elements are you trying to contain?

WebElement layout = Session.GetDesktopSession().findElementByName("name"); -> Is this the name of the application I want to use?

List list = Session.GetDesktopSession().findElementsByName("name"); --> Is this a list of applications running on the desktop?

What are the roles of each of these two codes?

example) Name = Winappdriver image

I still don't understand the movement between multiple applications.

What I understand is

  1. Run the desktop session first.
  2. Find the name of the application running on the desktop.
  3. Focus on the application using findElementByName ("Applicaiton name") in the desktop session

I am not finding an answer to the third process. I tried many things, but at least it didn't work in Java. Example code implemented in Java is required.

Nor did they solve the way they could control things that were not named. For example, how to control the right-click menu in the File Explorer

timotiusmargo commented 5 years ago

Hi @YeonwooJeong,

You don't have to use the list. I was simply showing of all the possible way to locate a UI element/elements using Name attribute.

The Name attribute that you provide to findElementByName or findElementsByName refers to UIA_NamePropertyId as described in https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-automation-element-propids

A UI element such as application window, button, text box, etc. may contain this attribute that you can use to locate that particular element if it happens to be unique in your session. So you can use the Name attribute of your main application window UI element to locate it and use the corresponding NativeWindowHandle of that element to create a new session.

Feel free to create a new bug requesting a Java example so that the WinAppDriver team can mark it as feature request.

YeonwooJeong commented 5 years ago

@timotiusmargo how to request? Is there a contact can contact?

timotiusmargo commented 5 years ago

You can create a new GitHub issue in this repository and clearly state the missing feature such as Missing Java sample for FindElementByName scenario. This will allow the WinAppDriver team or the community to respond to the issue with questions, estimates, and hopefully the feature itself.