Category Archives: Windows 8 CP

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:

Advertisements

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!

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.

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: the great mathematical enigma


You may have heard that beyond our little world of PowerShell and software testing boundaries many other things exist. For example, the mathematical theorems that are waiting for its solution. One of them is ‘what is the answer to the expression 2 + 2 / 2?’. I’m not a mathematician, you are perhaps too, so that what’s the reason to argue would it be 2, 3 or even 42?

Well, we are going only to test a program to confirm the readiness to such mathematical things. Meet the candidate: calc.exe!

Task: demonstrate how to test an application.

Requirements: use UIAutomation and TMX modules to report the results.

Solution: below is the code we run against the application under test (AUT):

ipmo [path]\UIAutomation.dll;
ipmo [path]\TMX.dll;

# Let's create a new test suite
# to clean up the data that are possibly out of the current interest
[TMX.TestData]::ResetData();
[UIAutomation.Mode]::Profile = [UIAutomation.Modes]::Presentation;
New-TMXTestSuite -Name 'Calculator testing' -Id calc;
Add-TMXTestScenario -Name 'Calculator menu' -Id calcmenu;
Add-TMXTestScenario -Name 'Caclucator simple calculations' -Id maths;

# start the application under test (AUT)
Start-Process calc -PassThru | Get-UIAWindow;
# now we've got the window in the
# [UIAutomation.CurrentData]::CurrentWindow variable

# set the initial state: Standard
Open-TMXTestScenario -Id calcmenu;
# we are going to save our test result regarding how the menu works here

# the main menu here is expandable/collapsible
# what can be learnt by issuing the following line of code:
# (Get-UIAMenuItem -Name View).GetSupportedPatterns()
Get-UIAMenuItem -Name View | `
 Invoke-UIAMenuItemExpand | `
 Get-UIAMenuItem -Name Standard | `
 Invoke-UIAMenuItemClick -TestResultName 'The Standard menu item is available' `
 -TestPassed -TestLog;
# the TestLog parameters logs the last line of code
# the TestPassed parameter informs that we have gotten the result we expected
# the TestResultName parameter gives the name to our test result
# test result Id is generated as we don't need to set it manually, this is just result

function calculateExpression
{
 param(
 [string]$modeName
 )
 # produce the input
 Get-UIAButton -Name 2 | Invoke-UIAButtonClick;
 Get-UIAButton -Name Add | Invoke-UIAButtonClick -TestResultName "The Add button is clickable $($modeName)" -TestPassed;
 Get-UIAButton -Name 2 | Invoke-UIAButtonClick;
 Get-UIAButton -Name Divide | Invoke-UIAButtonClick;
 Get-UIAButton -Name 2 | Invoke-UIAButtonClick;
 Get-UIAButton -Name Equals | Invoke-UIAButtonClick -TestResultName "The Equals button is clickable $($modeName)" -TestPassed;

# now we need to get the result
 # there is a difficulty: the name of a Text element (i.e., Label in .NET) is its value
 # okay, let's find all of them and our module highlight each
 #Get-UIAControlDescendants -ControlType Text | `
 # %{Get-UIAText -AutomationId $_.Current.AutomationId; `
 # sleep -Seconds 2; `
 # Write-Host "this was " $_.Current.Name $_.Current.AutomationId;}
 # the last, with Id = 158, is ours
 [int]$result = (Get-UIAText -AutomationId 158).Current.Name;
 $result;
}

# we must determine where we are
# as testers, we never believe, we check
# you might, for example, investigate into the second level menu:
#Get-UIAMenuItem -Name View | `
# Invoke-UIAMenuItemExpand | `
# Get-UIAMenu | `
# Get-UIAControlChildren | `
# %{Write-Host $_.Current.ControlType.ProgrammaticName $_.Current.Name $_.Current.AutomationId;}

# the easy way is to simple calculate the buttons
# MS UI Automation never returns what it can't see (by design, as it is intended for screen readers)
# the Standard mode - 31
# the Statictics mode - 33
# the Programmer mode - 48
# the Scientific mode - 53
[string]$testResultName = 'The Standard mode is available';
# to ensure that after changing the mode
# we are working with the actual window
Get-UIAWindow -ProcessName calc;
if ((Get-UIAControlDescendants -ControlType Button).Count -eq 31) {
 Close-TMXTestResult -Name $testResultName -TestPassed;
} else {
 Close-TMXTestResult -Name $testResultName -TestPassed:$false;
 # do additional actions if needed
}

# now we are going to test calculations so that
# we are switching to appropriate scenario
Open-TMXTestScenario -Id maths;
[string]$modeName = 'in the Standard mode';

calculateExpression $modeName; # in the Standard mode

# test the same in the Scientific mode
Open-TMXTestScenario -Id calcmenu;
Get-UIAMenuItem -Name View | `
 Invoke-UIAMenuItemExpand | `
 Get-UIAMenuItem -Name Scientific | `
 Invoke-UIAMenuItemClick -TestResultName 'The Scientific menu item is available' `
 -TestPassed -TestLog;

# check the mode we are in now
$testResultName = 'The Scientific mode is available';
# to ensure that after changing the mode
# we are working with the actual window
Get-UIAWindow -ProcessName calc;
if ((Get-UIAControlDescendants -ControlType Button).Count -eq 53) {
 Close-TMXTestResult -Name $testResultName -TestPassed;
} else {
 Close-TMXTestResult -Name $testResultName -TestPassed:$false;
 # do additional actions if needed
}

Open-TMXTestScenario -Id maths;
[string]$modeName = 'in the Scientific mode';
calculateExpression $modeName; # in the Scientific mode

# test reports are still ugly!!!
Export-TMXTestResults -As HTML -Path C:\1\calc_result.htm

After all, what is the answer? Okay, to choose the answer is 2 or 3 is not our mission. We only tested it, without the ambition to solve the mathematical problem…

%d bloggers like this: