Monthly Archives: April, 2012

Metro automation: the demo is published


The demo is published within the files of version 0.7.4 (though it’s almost 0.7.5).

The picture taken from a Windows Server 8 Beta host through the RDP connection:

Metro automation: the first script recorded!


With a bit of free time, I built a PowerShell host that works over Start Screen and recorded my first Metro script. As a host I used PoshConsole (a flamboyant shell, and I couldn’t use autocomplete for the UIAutomation cmdlets) with the manifest. At first, I tried to compile BGShell, but it falls each run, perhaps as a matter of using Windows Forms Aero for .NET 2.0 or something of this kind.

Okay, I ran PoshConsole, tested first clicks on tiles by commands issued manually and recorded a script: here it is, for your understanding what the structure of controls are (Inspect would show you similar results). In short, script does the following (I did the following):

– press Win to get to Start Screen

– click onto Photos, hovering near links to Photos, Skydrive photos, Facebook, Flickr, and text fields at the top of the screen

– click on Mail, select an account, hover between letters.

Below is the output:

Get-UIAWindow -AutomationId 'Start menu window' -Name 'Start menu' | `
	Get-UIAPane -AutomationId 'Root' -Name 'Start menu' | `
	Get-UIAList -AutomationId 'GridRoot' -Name 'Start Apps' | `
	Get-UIAPane -AutomationId 'ScrollViewer' | `
	Get-UIAPane -AutomationId 'content' | `
	Get-UIAListItem -AutomationId 'microsoft.windowsphotos_8wekyb3d8bbwe!Microsoft.WindowsLive.ModernPhotos' -Name 'Photos LargeTile1 Image';
		#InvokePattern
		#ValuePattern
		#ExpandCollapsePattern
		#GridItemPattern
		#SelectionItemPattern
		#ScrollItemPattern

Get-UIAPane -AutomationId 'Start menu window' -Name 'Start menu';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAText -Name 'Launching Photos';
		#ValuePattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAImage;
		#ValuePattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAText -Name 'SkyDrive photos';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIAListItem -Name 'Facebook photos

See your albums';
		#InvokePattern
		#SelectionItemPattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIACustom -Name 'Scrolling Container';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAText -Name 'Flickr photos' | `
	#TextChangedEvent triggered
#source title:  of the type Document | `
	Invoke-UIAListItemClick | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAText -Name 'Flickr photos';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIACustom -Name 'Scrolling Container' | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIAListItem -Name 'Facebook photos

See your albums';
		#InvokePattern
		#SelectionItemPattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIACustom -Name 'Scrolling Container';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAList | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAImage;
		#ValuePattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAText -Name 'Photos';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane -Name 'Windows Photos';
		#ValuePattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAText -Name 'APP PREVIEW';
		# no supported pattterns

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIAText -Name 'Photos';
		# no supported pattterns

Get-UIAWindow -AutomationId 'window' -Name 'PoSh - C:\1\poshconsole_f9bb2b127402\PoshConsole\bin\AnyCPU\Release (FileSystem)';
		#WindowPattern
		#TransformPattern
		#SynchronizedInputPattern

Get-UIAWindow -AutomationId 'window' -Name 'PoSh - C:\1\poshconsole_f9bb2b127402\PoshConsole\bin\AnyCPU\Release (FileSystem)' | `
	Get-UIADocument | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		#TextPattern
		#SynchronizedInputPattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane -Name 'Windows Photos';
		#ValuePattern

Get-UIAWindow -Name 'Photos' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Windows Photos' | `
	Get-UIACustom -Name 'Scrolling Container';
		# no supported pattterns

Get-UIAButton -AutomationId 'ImmersiveBackground' -Name 'Launch Start Menu' | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		#InvokePattern

Get-UIAWindow -AutomationId 'Start menu window' -Name 'Start menu' | `
	Get-UIAPane -AutomationId 'Root' -Name 'Start menu' | `
	Get-UIAList -AutomationId 'GridRoot' -Name 'Start Apps' | `
	Get-UIAPane -AutomationId 'ScrollViewer' | `
	Get-UIAPane -AutomationId 'content' | `
	Get-UIAListItem -AutomationId 'Microsoft.XboxLIVEGames_8wekyb3d8bbwe!Microsoft.XboxLIVEGames' -Name 'Xbox LIVE Games' | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		#InvokePattern
		#ValuePattern
		#ExpandCollapsePattern
		#GridItemPattern
		#SelectionItemPattern
		#ScrollItemPattern

Get-UIAWindow -AutomationId 'Start menu window' -Name 'Start menu' | `
	Get-UIAPane -AutomationId 'Root' -Name 'Start menu' | `
	Get-UIAList -AutomationId 'GridRoot' -Name 'Start Apps' | `
	Get-UIAPane -AutomationId 'ScrollViewer' | `
	Get-UIAPane -AutomationId 'content' | `
	Get-UIAListItem -AutomationId 'microsoft.windowscommunicationsapps_8wekyb3d8bbwe!Microsoft.WindowsLive.Mail' -Name 'Mail SwedishPod101.com, SwedishPod101 Word of the Day - 04/27/2012, Friday, April 27th, 2012 Your Swedish word of the day is: väg (Can you guess what it is? Click here';
		#InvokePattern
		#ValuePattern
		#ExpandCollapsePattern
		#GridItemPattern
		#SelectionItemPattern
		#ScrollItemPattern

Get-UIAWindow -Name 'Mail' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Mail' | `
	Get-UIAList -Name 'Message List' | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAListItem -Name 'From Группа разработчиков службы Hotmail, Subject Совет для Hotmail: как избавиться от спама, Received ‎April ‎18, ‎2012, Read' | `
	Get-UIACustom -Name 'Группа разработчиков службы Hotmail

Совет для Hotmail: как избавиться от спама

‎4/‎18/‎12

********************************************************************** Windows Live Hotmail(r) ********************************************************************** Hotmail защищает от спама. Hotmail использует множество инструментов для фил

From Группа разработчиков службы Hotmail, Subject Совет для Hotmail: как избавиться от спама, Received ‎April ‎18, ‎2012, Read' | `
	Get-UIAText -Name 'Совет для Hotmail: как избавиться от спама';
		# no supported pattterns

Get-UIAWindow -Name 'Mail' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Mail' | `
	Get-UIAList -Name 'Message List' | `
	Get-UIACustom -Name 'Scrolling Container' | `
	Get-UIAListItem -Name 'From Пользователь denisebaker68@hotmail.com, Subject Пользователь denisebaker68@hotmail.com хочет стать вашим другом в службе Windows Live, Received ‎April ‎17, ‎2012, Read' | `
	Get-UIACustom -Name 'Пользователь denisebaker68@hotmail.com

Пользователь denisebaker68@hotmail.com  хочет стать вашим другом в службе Windows Live

‎4/‎17/‎12

Пользователь Пользователь denisebaker68@hotmail.com хочет добавить вас в свой список друзей в службе Windows Live <https://xxxxxxxxx

From Пользователь denisebaker68@hotmail.com, Subject Пользователь denisebaker68@hotmail.com хочет стать вашим другом в службе Windows Live, Received ‎April ‎17, ‎2012, Read' | `
	Get-UIAText -Name 'Пользователь Пользователь denisebaker68@hotmail.com хочет добавить вас в свой список друзей в службе Windows Live <https://xxxxxxxxx' | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		# no supported pattterns

Get-UIAWindow -Name 'Mail' | `
	Get-UIAPane | `
	Get-UIAPane -Name 'Mail' | `
	Get-UIAMenuItem -Name 'Folders' | `
	#TextChangedEvent triggered
#source title:  of the type Document | `
	Invoke-UIAListItemClick | `
	#TextChangedEvent triggered
#source title:  of the type Document | `
	Invoke-UIAButtonClick | `
	#TextChangedEvent triggered
#source title:  of the type Document | `
	Invoke-UIAButtonClick | `
	#TextChangedEvent triggered
#source title:  of the type Document;
		#InvokePattern

Beware: navigation among Metro items


To whom it might frighten: multi-string names. There are no AutomationId here, only complicated names to get a control.

The Start Screen is much better:

What’s inside? The Mail application:

Kobo:

As can be seen from the last two figures, UI Automation is available to some extent. Nevertheless, we are far away from the ultimate happiness: there’s almost nothing to do in Solitaire.

Dictionary.com is also automation-ready:

It’s time to please ourselves with one more fascinating pic from the Store and say to Microsoft: “Think more about automation engineers _before_ the release”:

Happy testing!

End users’ wishes


What to do if a bit of free time occurs? Some features are too long to implement in these moments, the other are not built in the mind yet. There is a place to make small things the community may ask!

The Wish Lists published on the page are the place, feel free to write ideas to there – who knows which are easy to develop or document.

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?).

A word of appreciation: Windows 8 accessibility performance improvements


Compared to runs on a Windows 7 x64 box as well as on a Windows 2008 SP2 x64 box, the same script from the post gave the great difference in the work with the FindAll call:

to get the AutomationElement corresponding to the Workstation service (at the bottom of the grid) through the FindFirst call takes the same time as to get this element by using FindAll with iteration through the collection.

If you ran the script on a Window 7 or Windows 2008 box, you probably noticed that the latter way is slower than the former as much  as several times.

On the opposite, on a Windows 8 CP x64 box and on a Windwos Server 8 Beta box, both times are almost equal.

Viva, Microsoft UI Automation team! You embedded something (I think it’s caching always ON) that greatly improved the performance of control collections.

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;
%d bloggers like this: