microsoft / WinAppDriver

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

Is there any way to use WinAppDriver in attended automation using c# in visual studio 2017 #979

Open siddu1415 opened 4 years ago

siddu1415 commented 4 years ago

Want to use WinAppDriver in automation framework not in test scripts, attended automation scripts will work in user machines where i can't install WinAppDriver for each user, is there any way to use this similar like UIAutomationElement dll

pm90pl commented 4 years ago

No, it's not possible.

mills-andrew commented 4 years ago

Yes and No,

How are you running these test scripts on the user machines? through an agent?

siddu1415 commented 4 years ago

yes, i am using Microsoft UI Automation framework to write scripts for windows based applications, but not able to access UWP application elements through UI Automation, looking for alternatives

pm90pl commented 4 years ago

@KitoCoding could you provide more information about what you have in mind? I'm curious how is it possible to use WAD in such manner.

@siddu1415 but WAD is using UIA for communication with your app under test - also to interact with UWP apps.

Alternative solution (also based on UIA) - https://github.com/Roemer/FlaUI

mills-andrew commented 4 years ago

if he is running these through a remote agent, why not just copy the WAD to the bin folder of the agent and have it run from there. this sure sounds possible but i may under thinking the situation.

siddu1415 commented 4 years ago

To just minimize communication gap, i am writing scripts for attended process automation not testing automation for any single application, my attended automation solutions can be trigger through a standalone desktop tool which will be installed in user machines, it is very similar to UiPath Robot, In visual studio I am able to automate windows forms , wpf based apps using microsoft UIAutomatiom dll, but facing issue with UWP based applications, not able to capture elements from UWP based applications, but using WAD i am able to capture UWP based applications as well but it requires installation and administrator persmissions, there is the issue, i can not set this up in every user machine, if possible if i could use WAD( lets say some dll, .exe or nuget package) in visual studio with out installing and enabling ports, will be really helpful

mills-andrew commented 4 years ago

There is no install needed. WAD has a simple package with a DLL. The "install" is just a copy they do from a root folder.

C:\Program Files (x86)\Windows Application Driver

There is no install. just copy. and use the WinAppDriver.exe.

mills-andrew commented 4 years ago

If you are referring to communicating with its API. then you can build your own, or use appium.

siddu1415 commented 4 years ago

no i dont want use API, i want to explore above option,that more suitable for my requirment, if you have any sample code for this, could you please help me with that, everywhere i am findind sample code with some driverURL, thats where i struct

mills-andrew commented 4 years ago

i am confused, if you dont want to communicate with its API, then how are you going to automate?

siddu1415 commented 4 years ago

is there any possibility to use dll or WinAppDriver.exe in visual studio and access it's methods with out calling any api

mills-andrew commented 4 years ago

it sounds like you have a very clear goal in mind, and you blocking out other possibilities. There is no logical reason why you wouldn't hit up its API. if you are already installing a standalone desktop tool, then you can also have the exe be apart of that installation. Then all you have to do is build a framework that can communicate with its API.

if you are super against using the exe and talking to the API, then your next best bet is to reverse engineer the exe to identify its libraries and rebuild the entire thing from scratch to suit your needs. But thats just reinventing the wheel

mills-andrew commented 4 years ago

For example:

Here is some code that will start and stop the process in question.

Path : path to the winAppDriver and the executablename is WinAppDriver.exe. Fill in other variables where needed.

public void Start() { //Do we already have our process initialized? If not, lets create a new one if (this.mProcess == null) { //Attempt to find a process that already exists Process[] processes = Process.GetProcesses(); this.mProcess = processes.FirstOrDefault(m => m.ProcessName == executableName);

            if (this.mProcess == null)
                this.mProcess = CreateProcess();
            else
            {
                string cmdLine = GetCommandLine(mProcess);
                if(cmdLine.Contains("port"))
                    this.Port = Convert.ToInt32(cmdLine.Substring(cmdLine.LastIndexOf("=") + 1));
            }
        }
    }

    private Process CreateProcess()
    {
        //If one is already running then use it.
        //if (Process.GetProcessesByName("WinAppDriver").Length == 0)
            //Process.Start(@"C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe");

        Process process = new Process();
        process = new Process();
        process.StartInfo.FileName = Path.Combine(path, executableName);
        process.StartInfo.Arguments = mProcessArguments;
        process.Start();
        WaitUtils.Wait(() => Initialized() == true, this.initializeTimeout);
        return process;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="pProcess"></param>
    /// <returns></returns>
    private string GetCommandLine(Process pProcess)
    {
        using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + pProcess.Id))
        using (ManagementObjectCollection objects = searcher.Get())
        {
            return objects.Cast<ManagementBaseObject>().SingleOrDefault()?["CommandLine"]?.ToString();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public virtual void Stop()
    {
        if(this.IsRunning)
        {
            WaitUtils.Wait(() => Terminated() == true, this.mTerminationTimeout);
            this.mProcess.WaitForExit(3000);
        }

        //Implement catch all feature just in case.
        if(this.IsRunning)
            this.mProcess.Kill();

        this.mProcess.Dispose();
        this.mProcess = null;
    }
mills-andrew commented 4 years ago

There more to the code, but its just to give you a quick understand on how to access the exe.

siddu1415 commented 4 years ago

thank you very much, got it, let me try this once

siddu1415 commented 4 years ago

also could you help with some sample code or starting point for this "all you have to do is build a framework that can communicate with its API"

mills-andrew commented 4 years ago

Appium is an example of a framework that communicates with its API. Do you know about Appium?

siddu1415 commented 4 years ago

no i am not aware of it, but no problem, i will do some work arounds based on your suggestions above

mills-andrew commented 4 years ago

A post request to the API to build a new session might look something like this

"{\"desiredCapabilities\":{\"app\":\"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe\",\"deviceName\":\"WindowsPC\",\"platformName\":\"Windows\"},\"capabilities\":{\"firstMatch\":[{}]}}"

This json body defines how it will load up chrome.exe and build a session link to this application. The WinAppDriver is not following the new W3C WebDriver Protocol as of yet. There should be plans to implement it, but if you study up on the W3C WebDriver, then learning about the WinAppDriver will be a breeze.

https://github.com/w3c/webdriver

There are some differences here and there. but the jist is the same For example, here is a list of accepted api calls

https://github.com/microsoft/WinAppDriver/wiki/Supported-APIs

siddu1415 commented 4 years ago

what is this driverurl addressin below sample code, is this the default windowsdriver port?

private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability("app", CalculatorAppId); appCapabilities.SetCapability("deviceName", "WindowsPC"); session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities); Assert.IsNotNull(session);

mills-andrew commented 4 years ago

yes this is by default the host and port you have to connect to. "Windows Application Driver listening for requests at: http://127.0.0.1:4723/"

siddu1415 commented 4 years ago

is it required any administrator permissions to listen reqeusts? i read somewhere that we need admin access

siddu1415 commented 4 years ago

i am getting exception at this line session = new WindowsDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities);

mills-andrew commented 4 years ago

Well, you won't know until you try it lol

but the only concern i see, which i dont think is possible with the winAppDriver, is that the port is being used by someone else. If that is the case, you could get error messages like. "Unable to start because it is actively being refused" or something like that.

This script will find a free port but idn how to force winappdriver to listen on a different port. i'll look for a solution

    public static int FindFreePort()
    {
        int listeningPort = 0;
        Socket portSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            IPEndPoint socketEndPoint = new IPEndPoint(IPAddress.Any, 0);
            portSocket.Bind(socketEndPoint);
            socketEndPoint = (IPEndPoint)portSocket.LocalEndPoint;
            listeningPort = socketEndPoint.Port;
        }
        finally
        {
            portSocket.Close();
        }

        return listeningPort;
    }
mills-andrew commented 4 years ago

Take the day, look up tutorials before posting easy to solve errors. This youtube video helps a lot

https://www.youtube.com/watch?v=XAJVpvaEchY

siddu1415 commented 4 years ago

Sure, thank you very much for your help, really appriciate

joydeep19 commented 9 months ago

How to automate a application using putty using specflow c#??