Establishing a connection to an active process within Winappdriver with the utilization of JavaScript

As someone who is fairly new to working with JS and WinAppDriver, I am currently facing a challenge with testing a Windows-based "Click Once" application built on .Net. To launch this application, I have to navigate to a website through Internet Explorer and click on the "Install" button, which then opens up the application.

Once the application is up and running, I find myself unable to establish a connection for performing UI interactions using JavaScript. In the past, I used C# to loop through processes, search for a specific process name, grab its window handle, convert it to hexadecimal, add it as a capability, and create the driver - all successfully. Sample code snippet provided 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);
        }

However, my struggle lies in replicating this functionality in Javascript. Despite searching extensively, I failed to locate any relevant code examples. Referring to an example from this repo, I attempted the following approach in JS without achieving success:

import {By2} from "selenium-appium";
// Snippet of code for connecting to the application
async connectAppDriver(){
        // Code block for finding the process to latch onto
}

Unfortunately, I keep encountering an error message in WinAppDriver that reads:

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

This issue has been documented and reported under this ticket here, but I am still seeking a solution.

If anyone knows of any node packages or methods that could simplify obtaining the top-level window handle, I would greatly appreciate your suggestions. I am open to exploring alternative approaches in tackling this challenge when using JavaScript for WinAppDriver.

Answer №1

If anyone is struggling with this issue,

I found a workaround by developing an executable in C# that generates the hex of the application to connect based on the process name. Here is how it looks:

 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");
    }

I called this method from JS to retrieve the hex of the top level window handle, like so:

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();
}

After obtaining the hex, I connected to the application using the following approach:

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;
}

Answer №2

Resolution: If you are working with WebDriverJS (utilized by selenium / appium), opt for using getDomAttribute over getAttribute. It took me quite a while to figure this out!

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 now holds hex value :)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

No matter which method I try, the Selenium driver refuses to click the button

I am currently working on a script that scrapes information from the following website: QBCC Within this task, there are two dropdown menus and one input field. While I've successfully managed to work with the dropdowns, I've encountered some di ...

Displaying 'Undefined' instead of 'Cleared messages count' in the Clear Command

My goal is to display the number of deleted messages on an embed, but when the embed is sent, it shows bot deleted undefined messages. Here's a screenshot: https://i.sstatic.net/2GYxX.png I want it to show bot deleted ex: 15 messages. It works fine ...

Viewing the XML response generated by a JavaScript file (SOAP Request) on the IIS server

My current setup involves utilizing a calendar system with an API accessible via SOAP requests on an IIS server. Initially, my approach was to create an HTML page and use JavaScript to display the SOAP request response. However, the response did not retur ...

Having Trouble with Angular 6 Subject Subscription

I have created an HTTP interceptor in Angular that emits a 'string' when a request starts and ends: @Injectable({ providedIn: 'root' }) export class LoadingIndicatorService implements HttpInterceptor { private loadingIndicatorSour ...

When building with Angular using the "ng build" command, the JavaScript file names are altered

I'm currently learning Angular and I've noticed that when creating a new project with Angular CLI, files like runtime.js, polyfills.js, main.js, styles.css are generated. However, after running the ng build command, similar files can be found in ...

What is the best way to connect my 'Projects' folder to app.js within a React application?

import "bootstrap/dist/css/bootstrap.min.css"; import Navbar from './components/Navbar'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import Home from './components/Home'; import Project ...

Unforeseen outcomes of JavaScript when using the let and var keywords

In JavaScript, when using the var keyword to declare a variable, the JS engine assigns a default value of "undefined" at creation stage. console.log(message); // undefined var message = "My message"; However, with the let keyword: console.log(message); ...

Implement a code to apply to an image that is loaded dynamically

I have a situation on a page where an image is loaded via ajax within a wrapping div. I need to execute some code as soon as that image is loaded. Unfortunately, I am unable to modify the ajax call, which means using on('success') directly on the ...

List application now includes the capability of adding three items in one go, rather than just one

Furthermore, when the script is placed in the same file as the html, it results in the addition of two items simultaneously instead of three. var itemNum = 1; $("document").ready(function() { $("#addCL").click(function() { var itemId ...

A clever way to bypass the "Choose search engine" prompt using capybara, selenium, and chrome

Upon opening Chrome from capybara, I am encountering this screen: https://i.sstatic.net/TMn6SlwJ.png Since stack overflow images are not working for me, here is the image on imgur: This issue is causing errors in my specs. How can I bypass it? For examp ...

Struggling with rendering object in Next.js, receiving an error stating "map is not a function."

Currently, I am attempting to display data fetched from STRAPI using Graphql and Next.js. Fortunately, my event Adapter is functioning perfectly. However, when trying to showcase this data on the UI, an error occurs stating event.map is not a function. Whi ...

Utilize the Google Maps API to align an SVG symbol with the direction of an aircraft's

I have been struggling to update the rotation of the Google Maps API SVG aircraft symbol to display the correct heading as it moves. Although it initially loads with the correct heading, I can't seem to figure out how to dynamically update it. I' ...

Expanding the Number of Arguments Sent to a Callback Function

I have a scenario where I am using a method that sends a POST request and then triggers a specific callback function to manage the response: myService.verify(id, verificationCallback); function verificationCallback(err, response) { ... } My query is two ...

Getting the date from a datetime JSON - here's how!

How can I extract the date from a JSON datetime string like 2013-11-09T00:00:00 using either Jquery or JavaScript? ...

Receiving the error message "Unable to locate the module named 'distutils'" while attempting to execute my program

My Selenium bot works perfectly on my local Mac, but when I try to run it on a virtual Windows 10 machine through Google Cloud, I encounter the following errors: "Traceback (most recent call last): File "c:\Users\ahamed_a_1235\in ...

javascript + react - managing state with a combination of different variable types

In my React application, I have this piece of code where the variable items is expected to be an array based on the interface. However, in the initial state, it is set as null because I need it to be initialized that way. I could have used ?Array in the i ...

Executing Python scripts from a shared directory

Can individuals without Python installed run a Python Selenium script as long as all dependencies are available in a shared directory? For example, if the entire Python folder and its libraries are placed in a shared directory, would users be able to exec ...

ECharts - Version 3.1.6 Event Plugin

I am looking for advice regarding the management of two charts with reference to echars from Baidu (version 3.1.6). Is there a way to control both charts by engaging in a click event on one of them? In simpler terms, how can I capture and respond to the c ...

"Enhance your data management with Laravel and Vue.js by incorporating the powerful Matfish Vue-Table

Currently, I am utilizing matfish-vue-table2 along with server-side implementation. Below is my Laravel controller where I am able to retrieve the JSON response from the 'api/articles' URL: public function index() { $articles = Article::orde ...

AngularJS: Compile a particular template

One pre tag on the page contains dynamic text that is unknown during page load. This text may include ng commands, as shown below: <pre> Hello <span ng-click="test('args')">world</span> angular-JS! </pre> Since these ...