Monday, 4 February 2019

Some Scriblings

Installing WinAppDriver silently

/c "misexec /i "path_to_msi.msi" /quiet /passive /l "path_to_LogFile.txt""





-Pankaj Dhapola
Let's Think on it

Tuesday, 1 January 2019

Simple WinAppDriver Code for creating desktop session


I came across many situation where people want to start the application directly using WinAppDriver.
Sometimes, they come across many weird error and are stuck waiting for someone to resolve.

One of the alternative to this problem is to create a session of Windows Desktop and then finding the right Windows in your desktop session. This code is my personal favorite.


Code below

RemoteWebDriver WindowsDesktopSession;
DesiredCapabilities WindowsDesktopCapabilities;
IWebElement TargetWindow;

WindowsDesktopCapabilities = new DesiredCapabilities();
WindowsDesktopCapabilities.SetCapability("app", "Root");
WindowsDesktopCapabilities.SetCapability("deviceName", "WindowsPC");

WindowsDesktopSession= new RemoteWebDriver(new Uri("http://127.0.0.1:4723"), WindowsDesktopCapabilities);

TargetWindow = WindowsDesktopSession.FindElement(By.XPath( strTargetAppicationWindowsXPath));



There you go!

Now you have the "TargetWindow", start using this object to explore the elements present inside this Window.

-Pankaj Dhapola
Let's Think on it

Saturday, 11 November 2017

Code to save IWebDriver.PageSource in XML file

The Following snippet is most of the time used while working on Automation using WinAppDriver


driver - RemoteWebDriver instance


System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(driver.PageSource.ToString());
System.Xml.XmlTextWriter writer = 
     new System.Xml.XmlTextWriter(@"c:\App_To_XML.xml", 
                   new System.Text.UnicodeEncoding());
writer.Formatting = System.Xml.Formatting.Indented;
doc.WriteContentTo(writer);


-Pankaj Dhapola
Let's Think on it

Sunday, 1 October 2017

Why I think Psychology subject should be taught along with Computer Science

Continuing with the previous discussion

I argued Sam bhai that give me any automation tool or any software language to work upon and give me sometime, I should be able to start working on it easily!

He said "Anyone can do it, we have plenty of Tutorials available".

I said "But some of the proprietary tools don't have tutorials, apart from company's documentation and Limited Forum how you can excel at such tool?"

He has a suspicious look! and exclaimed "And on what basis do you say that with limited educational material you would be able to crack it up?"


Filling over another glass full of beer I said "Psychology and Behavioral pattern of the machine"

Stunned Sam bhai had this sense of understanding in his eyes and said "Go ahead! I would like hear more".


Lets not talk about the Human Psychology, its too complex to Understand. Psychology of machine is fixed and simple. Can be complex sometimes and that too depends on the creator of machine, one should bow to Creator of Matrix in Matrix Movie. You give an input to a machine/software and receive an output. Let me be a little metaphorical over here.

I believe if you want to be a good programmer, step into the shoe of compiler, think like a compiler and present the output like a compiler. It like being a compiler you will have to respond to each line of code according to the rules set by creator. Thinking like machine\compiler compelled me to say machine do have per-defined conscience.

I meant What do a psychiatrist do? He evaluates you by calmly listening you, ask you certain questions or sometimes ask you to share whatever you want. Let's take it at a minute level, its plan and simple stimulus-response pair. Can we relate this to machine as Input-Output pair?

Likewise if you want to be good programmer start evaluating the tool, start sending input code, remember the output, yeah it complains too i.e. error, and during the middle of conversation clarify some doubts i.e. put a breakpoints and check the value of a variable ;)

Imagine a java compiler as culmination of various great programmers in Sun microsystem (now Oracle). While creating compiler the compiler designer must have thought, let me code this way such that whoever is going to use this compiler will send such input and the output is provide in such format.

In short you can think that a compiler is actually a replica of the Programmer's Mind.

Can we think in this direction to Introduce Psychological Compilers (of-course with good conscience) where the future AI will behave in a predictive pattern.

-Pankaj Dhapola
Let's Think on it

Why an organization should not let anyone to code Automation Script

On Sep 17, 2017, I had a great discussion over couple of beer with one my good friend Sam (though he drinks sprite only) :D


Now we were discussing about latest trend in Software Test Automation, since I have been exploring on subjects like WinAppDriver, Galen Framework, XML based API Testing. After exchanging little ideas about these tools Sam came up with a new tool which is being currently been implemented in his company. Let me not name the tool, lets say it "Automation tool for Kids" or ATK.Why I named it that way, you will come to know, please proceed.

Sam is kind of high caliber Automation-cum-Software Developer.

Sam bhai told me this tool is awesome. He went for 5 day training for this tool. He said anyone can work on ATK. No need of in-dept knowledge of JavaScript or any other language.

I raised my eyebrow. How is that possible?

He went on explaining me why this tool would be a success. His company have asked manual testers and BA's to start working on this tool. I asked him about the test stability. He said he don't have the data yet but he was quite positive about less maintenance in regression suite.

One thing that has always bothered me is the Test Stability. Please understand my frustration, I have been working on Automation Testing Profile for around 8 years and have little good understanding of QTP/UFT, Selenium WebDriver, Test Complete, Coded UI and most of the time I have been working on Fixing the issues in Automation and I know exactly where an automation code will/has fail/failed.

Having this things in my mind I was kinda skeptical about the Test Stability. In my organization, we have got this great tool - basically a wrapper of Selenium WebDriver and nicely build. Just like any Keyword driven framework you just have to pass on the locator and data. Trust me I never faced an issue related to the code behind of this Keyword Driven framework based tool, nicely coded, nicely synchronized and very nicely configured.

Now where did the issue started. The basic issue was at the inception of this tool, it was targeted for Business Analyst and Manual Testers to write the scripts. Problem is when you ask a non-technical guy to code the automation script it will be easy for them to add steps like "ClickOnAnElement", "EnterAValueInAnElement" or "ValidateAValueIAnElement" but 
- What about the Synchronization?
- What about the correct Identification criteria or correct Locator? 
- What about the behavior of system?
- What about different ways of Validating a result?
- What about code re-usability and maintainability?
- What about scalability?

Without an understanding of Automation Framework Development, it would be unfair to expect good stability in Automation Suite. It doesn't matter which automation tool you use.

-Pankaj Dhapola
Let's Think on it

Friday, 11 March 2016

Handling Authentication Popup Dialog in Selenium WebDriver

It has been observed that Selenium WebDriver is unable to handle the Authentication Security Popup Dialog because the Authentication popup is originated from OS. Selenium WebDriver has the limitation to work only inside DOM.

So the basic workflow to mitigate this issue is to let this job to be assigned to external process using thread. Which means before hitting the URL or before the security pop up appears this code needs to be executed. This external process will wait for the security pop up to appear and then mitigate the situation.

I tried many solutions while researching over internet. Some advised AutoIT script, Sikuli,  shell scripting. Every other had some issues and inconsistent performance. I learned that mitigating this at OS level would definitely be a good solution. I was able to implement a code involving exploitation of User32.dll methods.

I was surprised about the performance of this piece of code which provided robust solution to handle the Authentication Security Popup. Below is the raw C# console application code, please customise this accordingly.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections;

namespace PopupHandler
{

    class Program
    {
        private const int WM_SETTEXT = 0x000C;
        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_CLOSE = 0xF060;
        public const int BM_CLICK = 0x00F5;
        public const int EM_SETPASSWORDCHAR = 0X00CC;

        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("User32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);
        [DllImport("User32.dll")]
        private static extern Int32 SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        private void HandlePopUp(string browser, string executionmode, string uid, string pwd)
        {
           if (browser.Equals("ie"StringComparison.InvariantCultureIgnoreCase))
            {
                if (executionmode.Equals("cancel"StringComparison.InvariantCultureIgnoreCase))
                {
                    // retrieve Windows Security main window handle
                    IntPtr hWnd = FindWindow("#32770""Windows Security");
                    int iterateForSecurityPopup = 0;
                    for (iterateForSecurityPopup = 0; iterateForSecurityPopup < 20; iterateForSecurityPopup++)
                    {
                        hWnd = FindWindow("#32770""Windows Security");
                        if (!hWnd.Equals(IntPtr.Zero))
                        {

                            SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
                            Environment.Exit(0);
                        }
                        System.Threading.Thread.Sleep(1000);
                    }
                    if (hWnd.Equals(IntPtr.Zero)) {
                        Console.WriteLine("Dialog with title Security Popup not found");
                    }
                }
                else (executionmode.Equals("ok"StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] data = { uid, pwd };
                    // retrieve Windows Security main window handle
                    IntPtr hWnd = FindWindow("#32770""Windows Security");
                    int iterateForSecurityPopup = 0;
                    IntPtr duihWnd;

                    for (iterateForSecurityPopup = 0; iterateForSecurityPopup < 25; iterateForSecurityPopup++)
                    {
                        hWnd = FindWindow("#32770""Windows Security");
                        if (!hWnd.Equals(IntPtr.Zero))
                        {
                            // Get DirectUIHandle
                            duihWnd = FindWindowEx(hWnd, IntPtr.Zero"DirectUIHWND""");
                            if (!duihWnd.Equals(IntPtr.Zero))
                            {
                                ArrayList childs = GetAllChildrenWindowHandles(duihWnd, 15);
                                int i = 0;
                                int j = 0;
                                while (i <= childs.Count)
                                {
                                    IntPtr edithWnd = FindWindowEx((IntPtr)childs[i], IntPtr.Zero"Edit""");
                                    if (!edithWnd.Equals(IntPtr.Zero))
                                    {
                                        // send WM_SETTEXT message to control
                                        SendMessage(edithWnd, WM_SETTEXT, IntPtr.Zeronew StringBuilder(data[j]));
                                        j++;
                                        if (j == 2) { break; }
                                    }
                                    i++;
                                }

                                i = 0;
                                while (i <= childs.Count)
                                {
                                    //Click on ok
                                    IntPtr btnOkhWnd = FindWindowEx((IntPtr)childs[i], IntPtr.Zero"Button""OK");

                                    if (!btnOkhWnd.Equals(IntPtr.Zero))
                                    {
                                        SendMessage(btnOkhWnd, BM_CLICK, 0, 0);
                                        break;
                                    }
                                    i++;
                                }
                            }
                        }

                       System.Threading.Thread.Sleep(750);
                    }

                    if (hWnd.Equals(IntPtr.Zero))
                    {
                        Console.WriteLine("Dialog Handle not present");
                    }

                }

           
            }


        }

        static ArrayList GetAllChildrenWindowHandles(IntPtr hParent, int maxCount)
        {
            ArrayList result = new ArrayList();
            int ct = 0;
            IntPtr prevChild = IntPtr.Zero;
            IntPtr currChild = IntPtr.Zero;
            while (true && ct < maxCount)
            {
                currChild = FindWindowEx(hParent, prevChild, nullnull);
                if (currChild == IntPtr.Zero)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    break;
                }
                result.Add(currChild);
                prevChild = currChild;
                ++ct;
            }
            return result;
        }

        static void Main(string[] args)
        {

            string browser = args[0];
            string mode = args[1];
            string uid = "";
            string pwd = "";

                uid = args[2];
                pwd = args[3];

            new Program().HandlePopUp(browser, mode, uid, pwd);


        }
    }

}



-Pankaj Dhapola
Let's Think on it

Sunday, 21 October 2012

Architect Object Respository in your own way in Automation Framework

Object repository has been one of the most important aspects of framework development.


I am not going to show how you gonna add objects in QTP Object repository or use the object repository manager of QTP. Well you could find all those stuff very well over Internet.

I have seen some people Manipulating Object repository usage in QTP.

At a very basic level how do you understand Object repository existence, why their is a need of OR?

 To explain it in a simple manner, every Automation tool has its own architectural aspect to store Object properties or Object identifying criteria at a common place for usage while automation script run session.

 For example,
  • Object Repository in QTP
  • Object Map in RFT
  • Object Browser in Test Complete
I have seen people using QTP based Object repository, some building their own object repository! Of-course as I always say usage of every scenario has its own pros and cons.

Do you understand building their own object repository and not using QTP based Object repository?

I guess your next question is how is that so?

Just give more attention to above paragraph in bold letters.

When I say a place where object properties are stored, you can use an XML file, and excel file, a text file etc., Now the challenge is how you will use these files while in QTP run session.
You can place the description strings in these files and use some powerful Vb Script functions to build scripts


Just try to decode the below Image Illustration





Above illustration is very raw type of code, my aim behind showing this illustration is being an Automation Test Engineer cum developer you can tweak
the Object Repository usage in your script. Many ways can be developed to design architectural aspects. Of-course to master on you architectural skills you need experience.

Please note that I have purposely use the name of objects as such for better understanding.

Other Variation I see is below, I learned this technique from one my mentor, whom I regard as one the best minds I ever met.












So in Above illustration, you can observe how you can mimic an OR in QTP. Of-course many other ways have been developed.
Note that don't bother about the Hierarchy column as of now.
 

My main intention of displaying above different technique is to make you understand how you can design your OR. People of great minds have done this in many ways.

-Pankaj Dhapola
Let's Think on it

Saturday, 15 September 2012

Library Files

This is a continuation

In an automation framework architecture library files plays an important role. Normally people try to built most generalized function and place them at separate and common place.

I see that people always ask me questions which one is good to use Action or functions? I have personal view on these to use Functions instead of Actions. Of-course every aspects have its own pros and cons. Some people may feel comfortable to use Actions rather than Functions.

Whenever I create a functions I always have an intentions in my mind whether I can make this functions more generalized? I have developed an habit to have function's maximum usability. But be caution think to make generalized function should not change your motto of creating it ;)


A function doesn't meant to only have the VBscript codes, of-course you can always have QTP script codes . Functions are often treated as keywords in QTP, now a keyword can be placed separately in excel file, text file, or XML file. so that you can design keyword driven framework.

While automating (developing script) a particular workflow/E2E test case, first I create scripts in Linear manner in a particular action. Later on I break down these workflow in smaller script parts, of-course to divide these you need to know other test cases also so that you can easily identify commonality in functionality. Don't worry if you are not able to identify commonality, just go ahead and as you move ahead with framework designing you will be able to know it.

Now, the divided code is bundled under functions with a name which could make sense, for example NavigateTo(strURL), Login(strUserName, strPassword), NavigateToPageMenu(strMenuName), LogOut()

In an attempt to make execution faster and in terms of maintenance we load the functions runtime by leveraging power of "ExecuteFile" method. See, when you associate the ".qfl" file with script, so when you want to move complete framework folder, you will have to re-associate the library files. Of-course while script development you would require to associate library file for debugging purpose. Later on after your code is fully developed you can use "ExecuteFile" method to make all functions available in QTP run session during runtime.

I will update some more ideas in future, ofcourse many more ideas related to Library files.

Now Talking about our Framework development, presuming I have functional knowledge of AUT. I decide to place functions in appropriate library file. When I say appropriate library file . . . I meant only those library files containing specific functions which are relevant to a particular module or Test Case should be loaded. It doesn't make sense if you have numerous function written in a library file and in runtime load, these function are available which are of no use.

I have seen people writing function in an unorganized fashion and a single library files are flooded with many functions which are sometimes create problem during maintenance. Ofcourse no harm with that, but I believe this as to be the best practices.

See below image for a gist I am trying to convey . . .













 In above framework folder structure you can see some library files example placed. I guess no need to explain library files other than "GlobalFunctions.qfl"

GlobalFunctions.qfl :- This is one its kind, you know as the name suggest I place all those functions which 
  • are repetitively used
  • needs to have global scope
  • are very generalized
For example functions like
FrameworkInitializer, LoadModuleBasedTestData, LoadGlobalDataVariablesFromGlobalDataxls, CreateOutputDataFile, InitializeLogs, WriteCurrentLogInLogFile, ReportPassFail . . .

I have purposefully named these functions to be more meaningful to you ;)

GlobalFunctions.qfl file is associated with all QTP TestScript. The decision to put functions in which library files solely depends on you, you have to design the architecture, you have to design the workflow of you framework, you have to decide when to load which library files.

-Pankaj Dhapola 
Think on it

Saturday, 18 August 2012

Object Repository & Descriptive Programming

What is an Object Repository?
As the name Suggest Object Repository (OR in Short) is place where QTP Test Objects properties and its values are stored.

Conceptually if we want to perform a task on any Objects like WebButton, WebEdit, WinEdit etc. what we look for? Naturally the Object's available methods/functions/sub on which we need to perform the task!

Now, how do you know or how do you identify whether you are clicking the right button or entering string in right TextBox (WinEdit/WebEdit)? So, what do you look for the right Button or TextBox?

Your answer maybe like
-The look and feel of Object should be like button
-It should contain text on button
-And if their are two button with same name then in which context the button is present, I shall click that one. Example button name is "Submit" context may be
  1. Click Submit to update record 
  2. Click Submit to Add the record

So ultimately what were you doing? Identifying Objects by their properties, right? This is how QTP does the same to identify Objects.

For in depth understanding with illustrations on how QTP Identify Objects, click here.

Also have a look at Object Repository GUI in QTP and Descriptive Programming in QTP

Now, lets look at below screenshot of OR & DP Code, try to catch the difference

Look at the highlighted part. You will understand the commonality or what is the basic thing QTP works with, i.e. Properties.

I was just wondering how could OR based Code is associated with Object Repository, I just opened the Script.mts file in notepad and then. . .






See the highlighted part, now you can imagine how QTP IDE has been designed and how could QTP OR and DP based code works. ;-)
Hope you are able to understand OR and DP!

I don't know what these highlighted part are, otherwise I could have been in Mercury inc. ;-)



-Pankaj Dhapola
Think on it!!!