Tag Archives: ControlType

Daily automation: dumping control’s genealogy


This is a new edition of the old post.

Note: this post is deprecated, please refer to my comment below.

One more way to find out where in the Automation tree a control resides is to use the Get-UIAControlAncestors cmdlet. We are told that TreeScope.Parent and TreeScope.Ancestors used as filter for search will call the functionality that is not yet implemented? However, the cmdlet does perform the search from the very bottom of the hierarchy to the topmost window. Let’s take Calculator and dump the control hierarchy:

Task: demonstrate using the search to the top cmdlet.

Requirements: perform search that consumes a part of control’s name and retrieve all the ancestors of the search result.

Solution: the following code prints out all the hierarchy in reverse order:

Set-StrictMode -Version Latest;

ipmo [path]\UIAutomation.dll;

# here we are searching for all the element whose names start with 'a'

Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -Name A* | `

%{Write-Host "===========================================================";

Write-Host "@{Name='$($_.Current.Name)';
AutomaitonId='$($_.Current.AutomaitonId);
ControlType='$($_.Current.ControlType.ProgrammaticName)'}";
$_ | Get-UIAControlAncestors | `

%{Write-Host "@{Name='$($_.Current.Name)';
AutomaitonId='$($_.Current.AutomaitonId);
ControlType='$($_.Current.ControlType.ProgrammaticName)'}";}};
Advertisements

Daily automation: command tabs enumeration


Having come with Office 2007, command tabs are seen in more and more applications. What are command tabs? These are just tab items, from a UIAutomation user’s point of view.

Task: open a command tab by its name. Work with elements inside it.

Requirements: provide a standard way to open a command tab and get controls placed on here.

Solution: the first example is how to open each command tab in an application. With OneNote, taken as an example because never stopping complaints against UI-based tests disturb me ;), we’ll activate all the command tabs, one by another.

[UIAutomation.Preferences]::OnSuccessDelay = 0;

Get-UIAWindow -pn onenote | `
Get-UIAControlDescendants -ControlType TabItem | `
%{
# set initial state before access each tab item
Get-UIATabItem -Name Home | `
Invoke-UIATabItemSelectItem -ItemName Home;

[void](Get-UIAButton -Name File*Tab | `
Invoke-UIAButtonClick);

# select a tab item
$_ | `
Invoke-UIATabItemSelectItem -ItemName $_.Current.Name;

# stop to see where we are
sleep -Seconds 2;

# print out the name of the current tab item
Write-Host "$($_.Current.Name)`t" `
     "$($_.Current.AutomationId)`t" `
     "$($_.Current.ClassName)";   }

As can be easily tested, changing the word onenote to, for example, winword will print out command tabs of Word. (The script tested with OneNote 2010 and Word 2010 on a Windows 8 CP box).

Now we are going to accomplish the second part of this task: printing out all the content of every command tab.

[UIAutomation.Preferences]::OnSuccessDelay = 0;

Get-UIAWindow -pn onenote | `
Get-UIAControlDescendants -ControlType TabItem | `
%{
# set initial state before access each tab item

Get-UIATabItem -Name Home | `
Invoke-UIATabItemSelectItem -ItemName Home;
[void](Get-UIAButton -Name File*Tab | `
Invoke-UIAButtonClick);

# select a tab item
$_ | `
Invoke-UIATabItemSelectItem -ItemName $_.Current.Name;

# stop to see where we are
sleep -Seconds 2;

# print out the name of the current tab item
Write-Host "$($_.Current.Name)`t" `
"$($_.Current.AutomationId)`t" `
"$($_.Current.ClassName)";

# enumerate down the hierarchy    Get-UIACustom -Name ($_.Current.Name) | `
Get-UIAControlDescendants | `
%{
# print out the name of the current tab item
Write-Host "$($_.Current.Name)`t" `
"$($_.Current.AutomationId)`t" `
"$($_.Current.ClassName)";
      }
   }

Note, here we don’t get the hierarchy from under tab items. Tab items become custom controls when they are clicked. Thus, we used here Get-UIACustom fed with the name of the current command tab.

Daily automation: crawling here and there


Sometimes, queries are not the best way to navigate along the Automation tree. Why? Get-UIA[ControlType] cmdlets return only one control. The Search-UIAControl cmdlet returns all controls that match, but it needs previously to run around all the Automation tree that may be too long in certain applications.

What if your only need is to get a few controls situated at the same level of the Automation tree? My choice is to get one and navigate to the next sibling. Theoretically, the control that a Get- cmdlet returned is the first sibling, i.e. navigating to the previous sibling is not demanded at the same extent as to the next sibling. Though, no one guarantees that the control you’ve been given is the first child of its parent.

Thus, several cmdlets are here to help you turning left or right when necessary.

Task: demonstrate how to navigate along the Automation tree.

Requirements: figure out which cmdlets are helpful regarding navigation.

Solution: the first example shows the mistake almost everyone makes. “It should be here, under this, why your cmdlets don’t work?” I hear similar questions regularly. Don’t be confused with your results: the control of your interest might be not here. Where? Anywhere? No, just one or more levels below the hierarchy. Let’s run the following code (all the pieces of code are based on the assumption that the UIAutomation module is loaded, of course):

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlChildren | %{ Write-Host $_.Current.ControlType.ProgrammaticName $_.Current.Name $_.Current.AutomationId; }

My Calculator returns three controls. Haven’t you been expecting that the Get-UIAControlChildren cmdlet would return all the buttons numbered from 0 till 9? Nay, they are level or levels below. Now, we’ll get all the descendants:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants | %{ Write-Host $_.Current.ControlType.ProgrammaticName $_.Current.Name $_.Current.AutomationId; }

This code returns tens and tens of controls. I even calculated to announce that this time it returned 73 controls:

(Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants).Count

The Search-UIAControl returns 75 objects (possibly, objects with empty name and automation id are being calculated in various ways), but somewhat slower: the cmdlet walks the Automation tree what requires much more process-to-process calls.

(Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -Name *).Count

So where are the buttons? Just refine the search at first:

(Start-Process calc -PassThru | Get-UIAWindow | Get-UIAControlDescendants -ControlType Button).Count

Calculator in the Scientific mode returned 53 buttons, both buttons with numbers and signs and control buttons like ‘Minimize the window’.
Okay, let’s repeat the question: where our buttons are? Which control might be their parent? The main window? A pane under the main window?

(Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAcontrolParent).Current.ControlType.ProgrammaticName

Right, a pane. The full list of ancestors for this button is provided by the Get-UIAControlAncestors cmdlet:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlAncestors | %{ Write-Host $_.Current.ControlType.ProgrammaticName $_.Current.Name $_.Current.AutomationId; }

The main window contains a pane, it in turn contains another pane, which button are placed on.
It’s time to navigate horizontally:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlNextSibling

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlNextSibling| Get-UIAControlNextSibling

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlNextSibling| Get-UIAControlPreviousSibling

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlPreviousSibling

The first line of code returns the button 0, the second – MR, the third – (any doubts?) 1, the fourth – 4.

Eventually, we are going to know which of buttons is the first. To achieve this goal, we’ll get a button, get its parent, and get the first child:

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlParent | Get-UIAControlFirstChild

Start-Process calc -PassThru | Get-UIAWindow | Get-UIAButton -Name 1 | Get-UIAControlParent | Get-UIAControlLastChild

The first button is MC, the last (don’t you think that the Get-UIAControlLastChild is the less usable cmdlet if even me avoiding to use it?) – ‘ten in the X degree’.

After the navigating crash course has been conpleted, you are able to sail to wherever your controls are!

Daily automation: collecting access keys and accelerators keys


Working with an application under test using the keyboard is not a thing that the majority of us loves. What to speak, Microsoft guys would rebel against such tests. Although I’m also not a big fan of keyboard imitation, the post brought me to an idea to collect keyboard short cuts into a list.

For example, you need to have the full list of short cuts for further consideration, test planning, etc. Maybe, you are worrying about how to test localization to many languages and such a dump would be valuable.

Task: use UIAutomation to collect all the available on the current screen of the AUT access keys and accelerator keys.

Requirements: to form a tab-separated list of controls and their keys.

Solution: below is an example that can collect two levels of the menu items (the main menu and one level deeper). It works not bad, but in the last test, mspaint, it gets in the endless loop.

The whole script kill the WordPress engine (only the sourcecode area:)), so that I divided it into parts. The whole script will in the samples within the next version, 0.7.3, today later or tomorrow.

Set-StrictMode -Version Latest;
cls
ipmo [path]\UIAutomation.dll;
function Out-ElementDetail

{
 param(
 [System.Windows.Automation.AutomationElement]$element,
 [int]$level,
 [string]$parentAccessKey
 )

[string]$accessKey = $element.Current.AccessKey;
 if ($accessKey.Length -eq 0) {
 $accessKey = "None";
 } else {
 if ($parentAccessKey.Length -gt 0) {
 $accessKey = `
 $parentAccessKey + "=>" + $accessKey;
 }
 }
 Write-Host "$($level)`t" `
 "$($element.Current.ControlType.ProgrammaticName)`t" `
 "$($element.Current.Name)`t" `
 "$($element.Current.AutomationId)`t" `
 "$($element.Current.AcceleratorKey)`t" `
 "$($accessKey)";
 try {
 $global:dict.Add($accessKey, $element.Current.Name);
 }
 catch {
 Write-Host "Error: $($element.Current.Name)`t$($accessKey)";
 }
}
function Enum-Children
{
 param(
 [System.Windows.Automation.AutomationElement]$windowElement,
 [int]$level
 )

try {
 $apppid = $windowElement.Current.ProcessId;
 $elements = $null;
 if ($level -eq 0) {
 Out-ElementDetail $windowElement 0;
 try {
 $null = $windowElement | Invoke-UIAMenuItemClick;
 $elements = `
 Get-UIAWindow -ProcessId $apppid | `
 Get-UIAControlDescendants -ControlType MenuItem,SplitButton,Custom,ListItem;
 }
 catch {
 $elements = $windowElement | Invoke-UIAMenuItemExpand | Get-UIAControlDescendants -ControlType MenuItem,SplitButton,Custom; #,ListItem;
 }
 }
 if ($elements -ne $null -and $elements.Count -gt 0) {
 foreach ($element in $elements) {
 Out-ElementDetail $element ($level + 1) ($windowElement.Current.AccessKey);
 [void]($element | Move-UIACursor -X 5 -Y 5);
 try {
 Enum-Children $element ($level + 1);
 }
 catch {}
 }
 }
 if ($level -eq 0) {
 try{
 $null = $windowElement | Invoke-UIAMenuItemClick;
 }
 catch {
 $null = $windowElement | Invoke-UIAMenuItemCollapse;
 }
 }
 }
 catch {}
}
function Report-AccessKeys
{
 param(
 [string]$startName,
 [string]$stopName
 )

 if ($stopName.Length -eq 0) {
 $stopName = $startName;
 }

 [UIAutomation.Preferences]::OnSuccessDelay = 300;
 Write-Host "Access Key report for $($startName)";
 Write-Host "Level`tControlType`tName`tAutomationId`tAcceleratorKey`tAccessKey";
 [System.Collections.Generic.Dictionary``2[System.String,System.String]]$global:dict = `
 New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]";
 $topLevelMenuItems = Start-Process $startName -PassThru | `
 Get-UIAWindow | `
 Get-UIAControlDescendants -ControlType ToolBar,MenuBar | `
 Get-UIAControlDescendants -ControlType MenuItem,SplitButton,Custom,ListItem;

 foreach ($element in $topLevelMenuItems) {
 Enum-Children $element 0;
 }

 Stop-Process -Name $stopName;
}

Report-AccessKeys services.msc mmc;
Report-AccessKeys compmgmt.msc mmc;
Report-AccessKeys devmgmt.msc mmc;
Report-AccessKeys calc;
Report-AccessKeys notepad;
Report-AccessKeys mspaint;

The sample script crawls around controls and writes all the collected to the screen and in a dictionary (one dictionary per a function call).

Homework: fix the script. Script never finishes up mspaint with control types selected to work with (less types selected allow the script to finish, but the output is too poor). Also, it needs support of deeper levels of the menu (have you seen vSphere Client 5.0?).

Daily automation: eliminating the fragility of tests


Why do test fail? It’s the question every automated tester investigated into. Today we’ll discuss unexpected changes in the software under tests. This topic is hardly relevant to developers or even to testers in projects where no inexplicable changes allowed (have you seen any?).

When a new build is baked, and all nobody-knows-what changes are baked in, your tests might not find something vital and omit a great amount of the product functionality or stop completely.

One of solutions we accepted is to enable the search using wildcards. To our surprise, the wildcard search within a not great number of controls works with the same speed as the exact search. Wildcard search within a great number of controls is slower than exact search, possibly the latter uses caching or some hidden indices that we can’t use. There is a place for further investigation. In case of the fruitless search, both searches use almost the same time, the time the timeout told.

Task: use UIAutomation to get a control by a fragment of its name.

Requirements: compare times that needed for exact-match search and wildcard search.

Solution: below is the script that runs a process, gets its window, gets a control by exact match or using wildcard and reports the time used (part of the samples package) :

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
[UIAutomation.Preferences]::OnSuccessDelay = 0;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching (one of few controls of the MenuItem type):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name File}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching (one of few controls of the MenuItem type):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name Fil*}).TotalSeconds
Stop-Process -Name mmc;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching (one of a heap of controls of the Edit):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name BranchCache}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching (one of a heap of controls of the Edit):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name Branch*}).TotalSeconds
Stop-Process -Name mmc;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching (one of few controls of the MenuItem type):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name File}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching (one of few controls of the MenuItem type):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name *il?}).TotalSeconds
Stop-Process -Name mmc;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching (one of a heap of controls of the Edit):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name Workstation}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching (one of a heap of controls of the Edit):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name ?orksta*i*n*}).TotalSeconds
Stop-Process -Name mmc;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching (one of few controls of the MenuItem type - it takes the full time timeout is set to):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name nothing}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching (one of few controls of the MenuItem type - it takes the full time timeout is set to):";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAMenuItem -Name not?ing}).TotalSeconds
Stop-Process -Name mmc;

# regular search
[UIAutomation.Preferences]::DisableExactSearch = $false
Write-host "exact matching:";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name nothing}).TotalSeconds
Stop-Process -Name mmc;

# search with wildcards
[UIAutomation.Preferences]::DisableExactSearch = $true
Write-host "wildcard matching:";
(Measure-Command {Start-Process services.msc -PassThru | Get-UIAWindow | Get-UIAEdit -Name ?othing}).TotalSeconds
Stop-Process -Name mmc;

As can be seen, the search among controls that are not huge in number is so fast as exact matching. However, when it works among a significant number of control of the type chosen, search is slowing down. Why? Possibly, there caching is needed. No answer at the moment. the third part of the test script clearly shows that in an unhappy case both types of search fail at the same speed, after timeout expires.

Thus, for small applications or separate parts of a big one, there is the reason to use wildcard wherever it’s possible. Just to eliminate surprises your developers might easily involve you in.

Daily automation: exercising mspaint. Part 1


MSPaint within Windows 7 is a fun toy. Multi-level system of menu (command-tabs and drop-downs), Quick Access Toolbar, Zoom are the things that do mspaint quite similar to the Big Brother and sample for all forever, Microsoft Office. Well, let’s get accustomed with these controls.

Task: use UIAutomation to work with cutting-edge controls, for this goal explain how to use the search cmdlet with application’s menus.

Requirements: perform actions with a picture by means of menu items.

Solution: at first, start the application (don’t I need offer a bit more help? :)). The first example is how to completely renew a picture, i.e. create a new white sheet.:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
# create a new picture
Get-UIAWindow -pn mspaint | Get-UIACustom -Name 'Application menu' | Invoke-UIACustomClick | Get-UIAMenuItem -Name 'New' | Invoke-UIAMenuItemClick;
try{
 Get-UIAWindow -Name 'Paint' -Seconds 3 | Get-UIAButton -Name "Don`'t Save" | Invoke-UIAButtonClick;
} catch {
 Write-Host "the previous picture was as clean as snow";
}

Here a question can be raised: ‘what should we do if UIAutomationSpy obstinately gives us the code to access the Paste button that is beneath the list of menu items we are working with?’ Okay, there is a fault. The spy may suggest using the control underneath the mouse pointer on its own. Two controls are under the cursor, and the poor application may don’t know which of them we are interested in. Who is impeding us from using the search cmdlet? Below is the way how we can investigate into what the menu list is:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;

(Get-UIAWindow -pn mspaint | Get-UIACustom -Name'Application menu' | Invoke-UIACustomClick | Search-UIAControl -Name 'New').Current;

Daily automation: dumping control’s genealogy


Note: this post is deprecated, please refer to my comment below and the last edition of this post.

One more way to find out where in the Automation tree a control resides is to use the Get-UIAControlAncestors cmdlet. We are told that TreeScope.Parent and TreeScope.Ancestors used as filter for search will call the functionality that is not yet implemented? However, the cmdlet does perform the search from the very bottom of the hierarchy to the topmost window. Let’s take Calculator and dump the control hierarchy:

Task: demonstrate using the search to the top cmdlet.

Requirements: perform search that consumes a part of control’s name and retrieve all the ancestors of the search result.

Solution: the following code prints out all the hierarchy in reverse order:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
# here we are searching for all the element whose names start with 'a'
Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -Name A* | `
 %{Write-Host "===========================================================";
 Write-Host "@{Name='$($_.Current.Name)'; AutomaitonId='$($_.Current.AutomaitonId); ControlType='$($_.Current.ControlType.ProgrammaticName)'}"; $_ | Get-UIAControlAncestors | `
 %{Write-Host "@{Name='$($_.Current.Name)'; AutomaitonId='$($_.Current.AutomaitonId); ControlType='$($_.Current.ControlType.ProgrammaticName)'}";}};

Daily automation: search for a specific control


Sometimes we don’t know the type of object we are searching for. Often, we don’t even want to know the type. For instance, we need to check the list of controls is represented on a form or wizard page. To have this task done, we need the way that led as directly to the control of our interest.

Another example is a rich form. This may be OWA (Outlook Web Access) or anything else with a grid or a list with data. If we need to get a particular control or controls, there’d be useful a search allowing us to type in a part of name.

These tasks can be easily accomplished with the Search-UIAControl cmdlet. Let’s see how to do that.

Task: demonstrate using the search cmdlet.

Requirements: perform search that consumes a part of control’s name.

Solution: the first search shown below is inside the Calculator window:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
[UIAutomation.Mode]::Profile = [UIAutomation.Modes]::Presentation;
cls;

# here we are searching for all the element whose names start with 'a'
Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -Name A*;

# here we get only button(s)
Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -ControlType button -Name A*;

# this code should return the same as the first code snippet,
# because there are only two types of controls whose names start with 'a'
Start-Process calc -PassThru | Get-UIAWindow | Search-UIAControl -ControlType button,menubar -Name A*;

The second code start the Control Panel window, searches for the Sound link, open the dialog and searches inside for the Speakers control. Which type does the control have? I don’t know unless I run the code:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
[UIAutomation.Mode]::Profile = [UIAutomation.Modes]::Normal;

# click the Start button
Get-UIADesktop | Get-UIAButton -Name Start | Invoke-UIAButtonClick;

# open the Control Panel window
Get-UIAListItem -Name 'Control Panel' | Invoke-UIAControlClick;

# search for the Sound dialog
$w = Get-UIAWindow -Name 'Control Panel'; # the name will be changed during the test
Get-UIAWindow -Name 'Control Panel' | Get-UIAEdit -AutomationId 'SearchEditBox' | Set-UIAEditText -Text 'sound';
sleep -Seconds 1; # for the Normal mode only
# if you are running this script with the
# [UIAutomation.Mode]::Profile = [UIAutomation.Modes]::Presentation
# set, you can cut out this sleep
# Otherwise, there happened someting like 'the window couldn't form itself without a bit of time'
# Thus, this is unavoidable timeout (at least a half of second)

# open the Sound dialog
#Get-UIAHyperlink -AutomationId 'name' -Name 'Sound' | Invoke-UIAHyperlinkClick;
#$w | Get-UIAHyperlink -Name 'Sound' | Invoke-UIAHyperlinkClick;
$w | Search-UIAControl -Name 'Sound' -Highlight | Invoke-UIAHyperlinkClick;

# search for the Speakers device
Get-UIAWindow -Name 'Sound' | Search-UIAControl -Name 'Speak*' -Highlight;

Daily automation: registering user’s clicks


Have you never desired to write all the actions the user of your application performed? What a pity, there’s no embedded logging in our application… Hey, no problem here! The today’s sample demonstrates how to write down all button clicks.

Task: register all the clicks that the user done during the session.

Requirements: use the module for dumping all the button click events happened after the application started.

Solution: for simplicity sake, let’s start Calculator and choose the Standard mode. Close the application and run the following code:

ipmo [path]\UIAutomation.dll;

# use the Get-UIAControlDescendants cmdlet to collect all the visible buttons
# use the Register-UIAInvokedEvent cmdlet to assign an event action to each button
Start-Process calc -PassThru | `
Get-UIAWindow | `
Get-UIAControlDescendants -ControlType Button | `
Register-UIAInvokedEvent -EventAction {param($src) "$($src.Current.Name) clicked" >> $env:TEMP\calc.log;}

After the code is processed by PowerShell, the file will contain all key pressings.

(MS) UIAutomation: performing a Win32 click on a VMware guest


Task: explain how to make your UI test script working in the VMware environment.

Requirements: provide scripters with recommendations.

Solution: sometimes you need to do a specific click. It might happen if a control does not support InvokePattern (thus, there’s no Invoke-UIA[ControlType]Cmdlet or there IS a cmdlet, but the control does not support the InvokePattern on its own). Usually it is not a problem: we have a Win32 click (Invoke-UIAControlClick) and cmdlets based on this click (Invoke-UIAControlContextMenu).

All of a sudden you may notice that surprisingly your click does not work. You are running the script on a VMware guest and the problem is that the cursor refuses positioning. In other words, the API function SetCursorPos does not work.

Theoretically, there might be used OpenInputDesktop, SetThreadDesktop and similar stuff. However, there is a much simplier way: just uninstall VMware Pointing device. With losing a bit of comfort, you’ll get your script working.

%d bloggers like this: