<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: pauliedoherty</title>
    <description>The latest articles on DEV Community by pauliedoherty (@pauliedoherty).</description>
    <link>https://dev.to/pauliedoherty</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F127155%2Fb7ea988b-50cd-4da7-93eb-e5062bf98c44.jpg</url>
      <title>DEV Community: pauliedoherty</title>
      <link>https://dev.to/pauliedoherty</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pauliedoherty"/>
    <language>en</language>
    <item>
      <title>The Painful Parts of End-to-End Test Automation for your Windows Application</title>
      <dc:creator>pauliedoherty</dc:creator>
      <pubDate>Wed, 27 Jan 2021 21:58:39 +0000</pubDate>
      <link>https://dev.to/beanworks/the-painful-parts-of-end-to-end-test-automation-for-your-windows-application-1dde</link>
      <guid>https://dev.to/beanworks/the-painful-parts-of-end-to-end-test-automation-for-your-windows-application-1dde</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;This post is targeted at all you test engineers who do not want to add C# and all the wonderful Visual Studio tools that come with it to your test automation stack. You’re thinking, since our web app and mobile app’s e2e testing are already implemented with NodeJS why should testing our windows app be any different?&lt;/p&gt;

&lt;p&gt;Here are the weapons we will be wielding to achieve this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A minimum of Windows 10 or Windows Server 2016 desktop&lt;/li&gt;
&lt;li&gt;An automation tool to drive your application under test (AUT) - &lt;a href="https://github.com/microsoft/WinAppDriver" rel="noopener noreferrer"&gt;WinAppDriver&lt;/a&gt; &amp;amp; &lt;a href="http://appium.io/" rel="noopener noreferrer"&gt;Appium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A compatible automation client - &lt;a href="https://webdriver.io/" rel="noopener noreferrer"&gt;WebdriverIO&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A test runner - &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;Mocha&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A tool to run tests without manual user logon - &lt;a href="https://www.poweradmin.com/paexec/" rel="noopener noreferrer"&gt;paexec&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;An Automation Server of sorts (details of this are out of scope of this post)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other handy extras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/appium/appium-desktop" rel="noopener noreferrer"&gt;Appium Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/windows/win32/winauto/inspect-objects" rel="noopener noreferrer"&gt;Inspect.exe&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;...Note: Many parts in this post are only vaguely covered because there are already so many great resources out there. The parts that are described in detail were difficult to find good resources on, hence this post...&lt;/em&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Pain Point 1 - Preparing Test Environment for Automation (lil' painful)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  WinAppDriver &amp;amp; Appium:
&lt;/h2&gt;

&lt;p&gt;WinAppDriver is Microsoft's in-house developed tool to automate Universal Windows Platform (UWP), Windows Forms (WinForms), Windows Presentation Foundation (WPF), and Classic Windows (Win32) applications and is developed with Appium integration in mind. WinAppDriver is what does the heavy lifting behind the scenes. It carries out our mouse clicks and keyboard presses as we request. The image below shows the communication flow of our solution:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbe24yizt6qgq6h2wt158.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbe24yizt6qgq6h2wt158.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Appium is a RESTful server that acts as a wrapper between WinAppDriver and your automation client. Appium accepts commands from WebdriverIO and forwards them to WinAppDriver. In response to a request, it returns a status code and logs to the automation client.&lt;/p&gt;

&lt;p&gt;To run WinAppDriver &amp;amp; Appium on our test environment we need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/Microsoft/WinAppDriver/releases" rel="noopener noreferrer"&gt;Download&lt;/a&gt; and install WinAppDriver&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development" rel="noopener noreferrer"&gt;Enable Developer mode&lt;/a&gt; on Windows&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these prerequisites installed you are ready to automate using WebdriverIO’s test runner - &lt;a href="https://webdriver.io/docs/gettingstarted.html" rel="noopener noreferrer"&gt;wdio&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Pain Point 2 - Configuring WebdriverIO and running your first test (somewhat painful)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  WebdriverIO
&lt;/h2&gt;

&lt;p&gt;WebdriverIO (wdio) is a Selenium-like client service that sends requests to Appium via &lt;a href="https://w3c.github.io/webdriver/" rel="noopener noreferrer"&gt;W3C WebDriver Protocol&lt;/a&gt;. This is the framework we will use to write our test cases and specify how they will run.&lt;/p&gt;

&lt;p&gt;Before proceeding, please initialize a &lt;code&gt;nodejs&lt;/code&gt; project in your users home directory. If you're unsure how to do this &lt;a href="https://philna.sh/blog/2019/01/10/how-to-start-a-node-js-project/" rel="noopener noreferrer"&gt;Phil Nash's guide&lt;/a&gt; is excellent. I have creatively decided to call my project &lt;code&gt;my-project&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Taking from WebdriverIO's &lt;a href="https://webdriver.io/docs/clioptions.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; let's set up the test-runner by opening the Command Prompt and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-project &amp;amp; &lt;span class="nb"&gt;cd &lt;/span&gt;my-project
npm &lt;span class="nb"&gt;install&lt;/span&gt; @wdio/cli
npx wdio config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will launch a helper utility where you choose what services and project structure you wish to use when running wdio. To get things started please mirror these selections:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03t84nzzj3p6tzae5l8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03t84nzzj3p6tzae5l8o.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your project file tree should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bizz71v1jxkentn62cn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7bizz71v1jxkentn62cn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wdio.conf.js&lt;/code&gt; is the file that holds the configuration properties of the entire communication flow diagram in the first section. It is now loaded with the properties needed to allow communications between our webdriver client and Appium server. However, we still need to define our &lt;a href="http://appium.io/docs/en/writing-running-appium/caps/" rel="noopener noreferrer"&gt;capabilities&lt;/a&gt;. Capabilities define which environment we are running Appium  on, which protocol Appium will use, and what AUT it will be automating. Let’s uphold tradition and use the classic calculator example. Below are the capabilities required to connect Appium to the calculator application on Windows Server 2019 along with other properties relevant to this post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// wdio.conf.js snippet&lt;/span&gt;
    &lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/wd/hub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4723&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;platformName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;windows&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;automationName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;windows&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;deviceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WindowsPC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C:&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;Windows&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;System32&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;win32calc.exe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;

    &lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;logPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;     &lt;span class="c1"&gt;// logs are friends&lt;/span&gt;
        &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="nx"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mocha&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="nx"&gt;specs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/test/specs/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to note here - &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defining appium in &lt;code&gt;services&lt;/code&gt; instructs wdio to start an Appium server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Runner&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt; and &lt;code&gt;baseUrl&lt;/code&gt; properties are used to connect wdio client to the host Appium server &lt;/li&gt;
&lt;li&gt;Defining &lt;code&gt;capabilities&lt;/code&gt; tells Appium what application to automate and what automation tool we want it to configure; &lt;code&gt;WindowsPC&lt;/code&gt; maps Appium to &lt;code&gt;WinAppDriver&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We define &lt;code&gt;mocha&lt;/code&gt; as the test &lt;code&gt;framework&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;We tell said &lt;code&gt;framework&lt;/code&gt; what location the &lt;code&gt;spec&lt;/code&gt; file are in&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More details on Appium/WinAppDriver can be found &lt;a href="https://github.com/appium/appium-windows-driver#windowsdriver-specific-capabilities" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Note:
&lt;/h3&gt;

&lt;p&gt;I highly recommend using &lt;a href="https://github.com/appium/appium-desktop" rel="noopener noreferrer"&gt;Appium-Desktop&lt;/a&gt; as a development tool to troubleshoot any Appium connectivity issues. You can  download it &lt;a href="https://github.com/appium/appium-desktop/releases/tag/v1.19.1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start Appium Desktop from Start Menu, open File -&amp;gt; New Session Window… and enter the &lt;code&gt;capabilities&lt;/code&gt; above in the 'Desired Capabilities' tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p6z6nfqugvhk7ip7yhb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p6z6nfqugvhk7ip7yhb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Start Session&lt;/code&gt; to connect Appium to calculator app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4tc0yix8pfn3foxfr76.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj4tc0yix8pfn3foxfr76.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you cannot connect to your AUT with capabilities in Appium-Desktop, you will also not be able to connect through wdio, so make sure to get things working here first. Here's a contrived error on Appium-Desktop to give an example of error logs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2dlp1hat27m11vjfktx7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2dlp1hat27m11vjfktx7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now with our capabilities sorted we can start writing test cases for the wdio client.&lt;/p&gt;




&lt;h1&gt;
  
  
  Pain Point 3 - Controlling app elements (pretty painful)
&lt;/h1&gt;

&lt;p&gt;Shifting attention to our test spec file &lt;code&gt;./test/spec/example.e2e.js&lt;/code&gt;, we can define code to send requests to the Appium server. One of the beauties of webdriver is that the client object is accessible anywhere in wdio’s scope so we can directly call its properties. Let’s do some quick math to verify our calculators &lt;code&gt;sum()&lt;/code&gt; functionality =&amp;gt; &lt;code&gt;2 + 2 = 4&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ./test/spec/example.e2e.js&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Quick math&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Two plus two is four&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;              &lt;span class="c1"&gt;// click 2&lt;/span&gt;
        &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~93&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;               &lt;span class="c1"&gt;// click +&lt;/span&gt;
        &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;              &lt;span class="c1"&gt;// click 2&lt;/span&gt;
        &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~121&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;              &lt;span class="c1"&gt;// click equals&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~150&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// get result&lt;/span&gt;
        &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4 &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// verify it equals 4 &lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to note here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test spec files are using &lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;mochajs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Webdriver uses &lt;a href="https://webdriver.io/docs/api/expect.html" rel="noopener noreferrer"&gt;expect&lt;/a&gt; for assertions&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://webdriver.io/docs/api/browser/$.html" rel="noopener noreferrer"&gt;selector&lt;/a&gt; method uses &lt;code&gt;~&lt;/code&gt; to identify the &lt;code&gt;AutomationId&lt;/code&gt;. There’s not much clear cut documentation on this but you can work back from &lt;a href="http://appium.io/docs/en/drivers/windows/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt; to figure it&lt;/li&gt;
&lt;li&gt;Yes, I did append a space on the &lt;code&gt;4&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are finally ready to run our tests! In the Command Prompt run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx wdio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s the result from &lt;code&gt;npx wdio&lt;/code&gt; without appending a space:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkbvzsfd3d0i3ul5frkd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkbvzsfd3d0i3ul5frkd3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here it is with appending a space:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxnipfxdjteo6u9to44xc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxnipfxdjteo6u9to44xc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, I cheated. I should have parsed the data before asserting. But I refuse to apologize.&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Note:
&lt;/h3&gt;

&lt;p&gt;Use &lt;a href="https://docs.microsoft.com/en-us/windows/win32/winauto/inspect-objects" rel="noopener noreferrer"&gt;inspect.exe&lt;/a&gt; to find the AutomationId of your elements. Open inspect.exe and hover mouse over element you wish to inspect. Here’s an example of the ‘2’ button on the calculator app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F98fy67hjh29e9uvrw9vv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F98fy67hjh29e9uvrw9vv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus concludes setting up automation of a windows desktop application. &lt;/p&gt;

&lt;p&gt;On a side note, &lt;a href="https://github.com/microsoft/WinAppDriver/tree/master/Samples/JavaScript/packages/webdriverio" rel="noopener noreferrer"&gt;here's&lt;/a&gt; a great example of a scalable, maintainable wdio project using the Page Object Model pattern.&lt;/p&gt;




&lt;h1&gt;
  
  
  Pain point 4 - Running WDIO in a CI/CD pipeline without manual access to the GUI (painful)
&lt;/h1&gt;

&lt;p&gt;What we have achieved so far is great for development and presentation purposes. But to provide real value and execute this in a CI/CD pipeline we will need some extra setup in our test environment. Keeping cost saving in mind, we will not want our test environment running when tests are not being executed. It also becomes clear that Remote Desktop (RDP) is not very useful when it comes to automated pipelines. This now presents an interesting challenge - how do we run our tests with no user interaction or manual login step? One way is to send the test command over ssh. This is what we will explore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Aside:&lt;/em&gt;&lt;/strong&gt; configuring communication to the test environment is out of scope of this post; there are lots of great articles on setting up ssh servers out there.&lt;/p&gt;

&lt;p&gt;This part assumes we are running our test environment in a cloud based CI/CD pipeline, therefore the test environment is not being accessed through the GUI via RDP nor is it sitting beside you on your desk. With all that in mind, let’s remotely run our test cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s1"&gt;'cd my-project &amp;amp; npx wdio'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hmmmm, we are met with a pleasant 500 server error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmnxibnnni00gkizhopch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmnxibnnni00gkizhopch.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s see what’s going on by checking our processes in parallel while wdio is attempting to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s1"&gt;'tasklist /fi "imagename eq node.exe" &amp;amp; tasklist /fi "imagename eq win32calc.exe"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1th6t4cszlk0kzeafpdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1th6t4cszlk0kzeafpdr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmmmm, &lt;code&gt;node.exe&lt;/code&gt; and &lt;code&gt;win32calc.exe&lt;/code&gt; are running as services on &lt;code&gt;Session# 0&lt;/code&gt;. Service processes on &lt;code&gt;Session# 0&lt;/code&gt; are reserved for user agnostic processes and do not run with a GUI. Therefore Appium/WinAppDriver has no GUI output for it to find the running calculator application which also doesn't have a GUI output. This is sad times for people hoping to test the GUI.&lt;/p&gt;

&lt;p&gt;Let’s take a step back to figure out what's going on. Let's open an RDP connection to our test environment. Here, we can directly run our tests, and in parallel check our running processes.&lt;br&gt;
Using the Command Prompt (cmd) on the test environment let's run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project &amp;amp; npx wdio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at the same time in a separate terminal run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tasklist /fi &lt;span class="s2"&gt;"imagename eq node.exe"&lt;/span&gt; &amp;amp; tasklist /fi &lt;span class="s2"&gt;"imagename eq win32calc.exe
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see the tests have ran successfully:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnma2qi76croldk399zgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnma2qi76croldk399zgs.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And our processes are showing an RDP Session which does use the GUI. All actual logged in users get assigned &lt;code&gt;Session# &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiba95rog5hw85c3y7z7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiba95rog5hw85c3y7z7h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve the issue in our CI/CD pipeline we must configure our test environment to run our code as a logged in user. This will allow &lt;code&gt;node.exe&lt;/code&gt; and &lt;code&gt;win32calc.exe&lt;/code&gt; to run as a GUI Session.&lt;/p&gt;

&lt;p&gt;To achieve this, we must do 2 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable Autologon  &amp;amp;&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;paexec&lt;/code&gt; to run processes as the System account user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This solution is stated by hepivax on &lt;a href="https://github.com/microsoft/WinAppDriver/issues/147#issuecomment-500903983" rel="noopener noreferrer"&gt;this thread&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable AutoLogon:
&lt;/h2&gt;

&lt;p&gt;Please use guide &lt;a href="https://docs.microsoft.com/en-us/troubleshoot/windows-server/user-profiles-and-logon/turn-on-automatic-logon" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  PAExec:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.poweradmin.com/paexec/" rel="noopener noreferrer"&gt;PAExec&lt;/a&gt; is an open-source equivalent of &lt;a href="https://docs.microsoft.com/en-us/sysinternals/downloads/psexec" rel="noopener noreferrer"&gt;PsExec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PAExec allows you to run interactive command-prompts on local and remote servers as the System user account (it can do a lot more too!).&lt;/p&gt;

&lt;p&gt;Let’s install it on our test server and add it to a System Variable location so we can run it from anywhere with &lt;code&gt;cmd&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.poweradmin.com/paexec/paexec.exe" rel="noopener noreferrer"&gt;Download&lt;/a&gt; &lt;code&gt;paexec.exe&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy and paste to &lt;code&gt;C:\Windows\paexec.exe&lt;/code&gt; (If you’re unsure of this step refer to &lt;a href="https://www.computerhope.com/issues/ch000549.htm" rel="noopener noreferrer"&gt;this&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Test &lt;code&gt;cmd&lt;/code&gt; has access to &lt;code&gt;paexec.exe&lt;/code&gt; by running
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;where paexec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it should return &lt;code&gt;C:\Windows\paexec.exe&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can run &lt;code&gt;paexec&lt;/code&gt; in command prompt for more details on its use cases.&lt;/p&gt;

&lt;p&gt;Now that PAExec is installed and accessible, we can open a Command Prompt with PAExec so that &lt;code&gt;cmd&lt;/code&gt; is running under System user. Let's do this and verify where we are in the file system by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;paexec -s cmd /C "cd"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking this command down:&lt;br&gt;
&lt;code&gt;paexec&lt;/code&gt; -&amp;gt; Executes paexec.exe&lt;br&gt;
&lt;code&gt;-s&lt;/code&gt; -&amp;gt; Flags PAExec to run requested process under System user&lt;br&gt;
&lt;code&gt;cmd&lt;/code&gt; -&amp;gt; Open Command Prompt&lt;br&gt;
&lt;code&gt;/C&lt;/code&gt; -&amp;gt; Tells PAExec to pass a command to Command Prompt&lt;br&gt;
&lt;code&gt;“cd”&lt;/code&gt; -&amp;gt; Once paexec runs Command Prompt as System user it executes &lt;code&gt;cd&lt;/code&gt; which returns the current directory path&lt;/p&gt;

&lt;p&gt;This outputs our System account user path, verifying we are running &lt;code&gt;cmd&lt;/code&gt; as System user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fan0y9kg3g9yciz9obaxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fan0y9kg3g9yciz9obaxr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now any command we choose to execute in the Command Prompt with PAExec will run under the System user&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;...piecing it all together&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Over in our test automation server (or whatever you are using to remotely trigger your test suite), run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s1"&gt;'paexec -s cmd /C "cd C:\Users\${USER}\my-project &amp;amp; npx wdio"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; Remember the new path is required here because we opened a &lt;code&gt;cmd&lt;/code&gt; window from the System user account with PAExec.&lt;/p&gt;

&lt;p&gt;...And in parallel check that &lt;code&gt;node.exe&lt;/code&gt; and &lt;code&gt;win32calc.exe&lt;/code&gt; are running as a logged on user with GUI access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IP_ADDRESS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="s1"&gt;'tasklist /fi "imagename eq node.exe" &amp;amp; tasklist /fi "imagename eq win32calc.exe"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at our processes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyvtsawyc94e4ijt5irdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyvtsawyc94e4ijt5irdm.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see they are running under a &lt;code&gt;Session# &amp;gt; 0&lt;/code&gt; and Voila! Test executed successfully.&lt;/p&gt;

</description>
      <category>testautomation</category>
      <category>windows</category>
      <category>appium</category>
      <category>webdriverio</category>
    </item>
  </channel>
</rss>
