2

I am fairly new to JS/Winappdriver.

The application I am trying to test is a windows based "Click Once" application from .Net, so I have to go to a website from IE and click "Install". This will open the application.

Once the application is running, I have no way to connect the application to perform my UI interactions while using JavaScript.

Using C#, I was looping through the processes looking for a process name, get the window handle, convert it to hex, add that as a capability and create the driver - it worked. Sample code below,

public Setup_TearDown()
        {
            string TopLevelWindowHandleHex = null;
            IntPtr TopLevelWindowHandle = new IntPtr();
            foreach (Process clsProcess in Process.GetProcesses())
            {
                if (clsProcess.ProcessName.StartsWith($"SomeName-{exec_pob}-{exec_env}"))
                {
                    TopLevelWindowHandle = clsProcess.Handle;
                    TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
                }
            }
            var appOptions = new AppiumOptions();
            appOptions.AddAdditionalCapability("appTopLevelWindow", TopLevelWindowHandleHex);
            appOptions.AddAdditionalCapability("ms:experimental-webdriver", true);
            appOptions.AddAdditionalCapability("ms:waitForAppLaunch", "25");
            AppDriver = new WindowsDriver<WindowsElement>(new Uri(WinAppDriverUrl), appOptions);
            AppDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);
        }

How do I do this in Javascript ? I can't seem to find any code examples. Based on an example from this repo, I tried the following in JS to find the process to latch on to but without luck.

import {By2} from "selenium-appium";
// this.appWindow = this.driver.element(By2.nativeAccessibilityId('xxx'));
        // this.appWindow = this.driver.element(By2.nativeXpath("//Window[starts-with(@Name,\"xxxx\")]"));
        // this.appWindow = this.driver.elementByName('WindowsForms10.Window.8.app.0.13965fa_r11_ad1');
        // thisappWindow = this.driver.elementByName('xxxxxxx');

async connectAppDriver(){
        await this.waitForAppWindow();
        var appWindow = await this.appWindow.getAttribute("NativeWindowHandle");
        let hex = (Number(ewarpWindow)).toString(16);
        var currentAppCapabilities =
            {
                "appTopLevelWindow": hex,
                "platformName": "Windows",
                "deviceName": "WindowsPC",
                "newCommandTimeout": "120000"
            }
        let driverBuilder = new DriverBuilder();
        await driverBuilder.stopDriver();
        this.driver = await driverBuilder.createDriver(currentEwarpCapabilities);
        return this.driver;
    }

I keep getting this error in Winappdriver

{"status":13,"value":{"error":"unknown error","message":"An unknown error occurred in the remote end while processing the command."}}

I've also opened this ticket here.

It seems like such an easy thing to do, but I couldn't figure this one out.

Any of nodes packages I could use to get the top level window handle easily?

I am open to suggestions on how to tackle this issue while using JavaScript for Winappdriver.

Venkat Rao
  • 121
  • 2
  • 13

2 Answers2

2

Hope this helps some one out there,

Got around this by creating an exe using C# that generated hex of the app to connect based on the process name, it looks like something like this.

 public string GetTopLevelWindowHandleHex()
    {
        string TopLevelWindowHandleHex = null;
        IntPtr TopLevelWindowHandle = new IntPtr();
        foreach (Process clsProcess in Process.GetProcesses())
        {
            if (clsProcess.ProcessName.StartsWith(_processName))
            {
                TopLevelWindowHandle = clsProcess.Handle;
                TopLevelWindowHandleHex = clsProcess.MainWindowHandle.ToString("x");
            }
        }
        if (!String.IsNullOrEmpty(TopLevelWindowHandleHex))
            return TopLevelWindowHandleHex;
        else
            throw new Exception($"Process: {_processName} cannot be found");
    }

Called it from JS to get the hex of the top level window handle, like this,

async getHex () {
    var pathToExe =await path.join(process.cwd(), "features\\support\\ProcessUtility\\GetWindowHandleHexByProcessName.exe");
    var pathToDir =await path.join(process.cwd(), "features\\support\\ProcessUtility");
    const result = await execFileSync(pathToExe, [this.processName]
            , {cwd: pathToDir, encoding: 'utf-8'}
            , async function (err, data) {
                console.log("Error: "+ err);
                console.log("Data(hex): "+ data);
                return JSON.stringify(data.toString());
            });
    return result.toString().trim();
}

Used the hex to connect to the app like this,

async connectAppDriver(hex) {
    console.log(`Hex received to connect to app using hex: ${hex}`);
    const currentAppCapabilities=
        {
            "browserName": '',
            "appTopLevelWindow": hex.trim(),
            "platformName": "Windows",
            "deviceName": "WindowsPC",
            "newCommandTimeout": "120000"
        };
    const appDriver = await new Builder()
        .usingServer("http://localhost:4723/wd/hub")
        .withCapabilities(currentAppCapabilities)
        .build();
    await driver.startWithWebDriver(appDriver);
    return driver;
}
Venkat Rao
  • 121
  • 2
  • 13
0

Solution: In WebDriverJS (used by selenium / appium), use getDomAttribute instead of getAttribute. Took several hours to find :(

element.getAttribute("NativeWindowHandle")
POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
Command not implemented: POST: /session/270698D2-D93B-4E05-9FC5-3E5FBDA60ECA/execute/sync
HTTP/1.1 501 Not Implemented

let topLevelWindowHandle = await element.getDomAttribute('NativeWindowHandle')
topLevelWindowHandle = parseInt(topLevelWindowHandle).toString(16)

GET /session/DE4C46E1-CC84-4F5D-88D2-35F56317E34D/element/42.3476754/attribute/NativeWindowHandle HTTP/1.1

HTTP/1.1 200 OK
{"sessionId":"DE4C46E1-CC84-4F5D-88D2-35F56317E34D","status":0,"value":"3476754"}

and topLevelWindowHandle have hex value :)