Monthly Archives: February, 2012

(MS) UIAutomation: all about a combo box


Task: automate combo box selection.

Task #2: provide a homework helping to learn the control.

Requirements: describe both getting the selection and selecting list items.

Solution: below is the preparation (services.msc is already running, select a service, open the context menu, click Properties):

Get-UIAWindow -Name Services | `
Get-UIADataGrid | `
Get-UIADataItem -Name Alerter | `
Invoke-UIAControlContextMenu | `
Get-UIAMenuItem -Name Properties | `
Invoke-UIAMenuItemClick;

If you are sitting against a Windows 7 box, select for our test another service, for example, BranchCache.

Now the combo box can be seen. It has three or four values (I’m again doing the testing on a Windows XP box as I care about working on older and the newest operating systems): Automatic, Manual, and Disabled. There might or mightn’t be two ‘Automatic…’ items.

How to get what is selected now? Do so:

$((Get-UIAWindow -p mmc | Get-UIAComboBox | Get-UIAComboBoxSelection)[0]).Current

Now, is there a way to set a selection? Who roared ‘SetFocus; SendKeys’? Shut up, it’s not a sport but a torture. If a control is healthy and developers’ hands are sewn directly to shoulders, we can and we must use patterns.

Get-UIAWindow -p mmc | `
Get-UIAComboBox | `
Invoke-UIAComboBoxExpand | `
Get-UIAList | `
Get-UIAListItem -Name Automatic | `
Invoke-UIAListItemSelectItem -ItemName Automatic | `
Invoke-UIAListItemClick;

Too long? Let’s shortenize:

Get-UIAWindow -p mmc | `
Get-UIAComboBox | `
Invoke-UIAComboBoxExpand | `
Get-UIAListItem -Name Automatic | `
Invoke-UIAListItemSelectItem -ItemName Automatic | `
Invoke-UIAListItemClick;

We managed to delete only the Get-UIAList cmdlet. Why?
1) All the Get- cmdlets can perform search from the point they’ve been given with. Given a window, a childwindow or a control, from any of that start, a Get- cmdlet (excluding Get-UIAWindow as it does not have the -InputObject parameter) can continue the search down the Automation tree.
2) All the Invoke- (and pattern-cmdlets Get- and Set- like Get-UIAComboBoxSelection. Recognize them in a way: Get/Set-UIA[ControlType][Pattern name or abbreviation]) cmdlets can’t perform any search. They should be fed with a pipeline from a Get- cmdlet or a cmdlet that passed thru (-PassThru’ed) the object of the AutomationElement type.

To shortenize even more, you may cut out the first call, Get-UIAWindow (as it’s always stored in the [UIAutomation.CurrentData]::CurrentWindow variable), but be very attentively doing so: if you/your test Get-s a window (the main or an active child), closes it and tries to work with subsequent calls of Get-UIAWindow, error definitely will appear.

Homework: practisize working with the combo box, try another values, get the selection (I suppose that you know what is the difference between the selected list item and the selected list item that is braced inside the dotted box), save selection to a file, change selection, read it back from the file you’ve created, set the saved selection to the combo box, and do it until a new post got published. ­čÖé

Advertisements

(MS) UIAutomation: how to be informed if a control disappears…


An interesting question has been raised yesterday: how UIAutomation help to deal with a control that is disappearing. As known, MS UIAutomation works with only controls that are visible. It’s either ideology and technical limitation.
How the button I mentioned can disappear? For example, this is a button serving a progress bar of a wizard with the label Stop on its face. The progress bar achieves 100% and the button hides.

Using such an awkward code is not a solution:

while (Get-UIAWindow -p processname | Get-UIAButton -n Stop)

Here comes the help again from MS UI Automation: StructureChangedEvent provides us with six types of EventID, among others is the one we needed – ChildRemoved.

Task: wait for a button to be out of sight.

Requirements: get a signal from the button that can triger the main code. Use StructureChangedEventHandler.

Solution: the following sample represents the use of StructureChangedEvent

ipmo .\UIAutomation.dll
[bool]$global:buttonVisible1 = $true;
[bool]$global:buttonVisible2 = $true;
[bool]$global:buttonAddedAgain = $false;
Get-UIAWindow -n ShowHideButton | Get-UIAButton -n Button | Register-UIAStructureChangedEvent -ChildRemoved -EventAction {"01" >> c:\report.txt; $global:buttonVisible1=$false; "1" >> c:\report.txt;} -Verbose
Get-UIAWindow -n ShowHideButton | Get-UIAButton -n Button | Register-UIAStructureChangedEvent -ChildRemoved -EventAction {"02" >> c:\report.txt; $global:buttonVisible2=$false; "2" >> c:\report.txt;} -Verbose
Get-UIAWindow -n ShowHideButton | Register-UIAStructureChangedEvent -ChildAdded -EventAction {$global:buttonAddedAgain=$true; "3" >> c:\report.txt;} -Verbose
#sleep -Seconds 5
#Write-Host "1" $global:buttonVisible1
#Write-Host "2" $global:buttonVisible2
#Write-Host "3" $global:buttonAddedAgain

while ($global:buttonVisible1 -eq $true -and $global:buttonVisible2 -eq $true){
	sleep -Seconds 1;
	Write-Host "1" $global:buttonVisible1
	Write-Host "2" $global:buttonVisible2
	Write-Host "waiting...";
}
Write-Host "completed";
Write-Host "1" $global:buttonVisible1
Write-Host "2" $global:buttonVisible2
Write-Host "3" $global:buttonAddedAgain

The sample works with a simple program that is a form with two buttons. One button is Show/Hide button, its click event shows/hides the second button.

Just run the program (samples 0.6.2 or newer), after that run the script (it subscribes to events) and click one or several times upon the Show/Hide button.
Soon or later you’ll see both global variables set to $false, and the third to $true.

Restrictions may apply, to read more about the event and which eventId can be used on a purpose, visit StructureChangedEventArgs Constructor

(MS) UIAutomation: administrative rights may be necessary on comtemporary operating systems


Problem: the framework behaves strangely.

Requirements: reclaim the stability.

Solution:┬árun your powershell console or IDE under domain admin credentials or through Run As Administrator. When working with something like Administrative tools (services.msc or compmgmt.msc, or ADUC), or regedit, or your company’s administrative tool, there might be a waterfall of errors, sometimes amazing. The answer is simple: use administrative credentials while working with administrative applications through inter-process┬ácommunication.

(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.

(MS) UIAutomation: using the script recorder


Task: start working with the script recorder.

Requirements: to be able to work with the recorder from the command line.

Solution: The script recorder is the cmdlet that was in the framework from almost its commencement. In fact, how to write the code? The scripter needs to have the following:
– a tool for recognizing AutomationID, ControlType and Name of controls that are under test
– a tool that can inform about supported patterns
– knowledge about cmdlets and parameters, some experience with the framework
– log problems

A tester needs significantly more:
– a way to get and store test results
– detailed log
– saving screenshots on any situation when it’s required
– custom parameters (the need to parametrize as much as possible to multiply the tests)

The script recorder helps in the needs of the scripter. The needs of a tester are resolved in the framework by different means. Issue the following command:

Start-UIARecorder -NoClassInformation -NoUI -NoScriptHeader -WriteCurrentPattern -Seconds 60

Now you can move the mouse cursor to the controls of your interest, performs actions like clicks and editing the text. The script recorder is far away of being finished, nevertheless its help may be very useful.
Remember that for now it records all it managed to record without separation from unnecessary windows and controls. Nevertheless, it might help at least in syntax.

(MS) UIAutomation: how to find a proper cmdlet


Task: teach how to find cmdlets for your tests.

Task #2: provide a task to practise.

Requirements: provide examples on how to find cmdlets.

Solution: most of questions from the people who started working with the UIAutomation module are about how to get a control and how to deal with it. In other words, better to say: in terms of the UIAutomation module, Get- cmdlets and Invoke- cmdlets.

In UI Automation, there are several important properties of a control:
– AutomationID (it can be a name of a control, usually the Name property as it seen in SharpDevelop or Visual Studio. Though, sometimes it can be generated by the application)
– Class (ClassName in terms of MS UI Automation. This property is platform-dependent and hardly recommended for use)
– Name (usually the Text property in your IDE. Therefore, should be used not with an every control. For example, there’s no much sense to use the Name property with a Text Box, since this property is subject to change during the test)
– ControlType (even this can be platform-dependent: compare the grid in services.msc (DataGrid in Windows XP) and services.msc (List in Windows 7). The same thing has been observed for Common Controls on Windows 2000 and Windows XP many years ago, by means of other tools)

The UIAutomation PowerShell framework is built in a way that you’ll be needing rarely in setting the last property, the ControlType. This is done, in most situations, automatically by aliasing. That means that

Get-UIATextBox -a UserNameBox

is the same as

Get-UIAControl -ControlType Edit -a UserNameBox

Furthermore, TextBox, LinkLabel, GroupBox are also aliases to the UI Automation’s Edit, Hyperlink, Group. This is done for achieving two purposes:
– simplifying the search across the cmdlets
– readability of the code

How to find the cmdlets, the topic of a post? Consider the following piece of code:

Get-Command -Module uia* *textbox*

This command returns several cmdlets that are intended to be used with a textbox.

If you need an action that you can perform to a control, run something like this:

Get-Command -Module uia* *click*

This command returns all the cmdlets that can perform a click.

Note: the list of actions (patterns) you may use with controls can be seen here: http://msdn.microsoft.com/en-us/library/ms752362.aspx

Note: not every control supports a pattern even if it is in the list http://msdn.microsoft.com/en-us/library/ms750574.aspx. It depends even on properties the developer set to a control. AccessibilityRole, for instance. If control does not support a pattern, the cmdlet returns an exception. It also may depends on a time of day:), I mean the time when a control is in one state when the pattern is supported, and other time the control can be in somewhat other state, and the pattern may not be supported.

Note: there are several ways to find out which patterns are supported by the control right now:
– enum currently supported patterns

(Get-UIAWindow -p mmc | Get-UIADataGrid).GetSupportedPatterns()

– use UIA Verify 1.0 or 2.0 (the first has a problem with hovering, the latter does show less patternt than the first). The link to the project: http://uiautomationverify.codeplex.com/
– use the script recorder with the parameter -WriteCurrentPattern (it’s very likely that the parameter will be renamed in the next version, and the recorder itself is a subject of near-future rewriting. Nonetheless, you can play it around right now).

Homework: find the cmdlets that are targeted to work with Tab, TabItem (both control can be found in the MMC), Button. Try to find appropriate patterns (Invoke- cmdlets) and perform actions with the controls.

(MS) UIAutomation: what if -PassThru:$false


Task: demonstrate return values.

Task #2: provide a field for learning the module.

Requirements: provide examples with two types of return values.

Solution: run the following code:

(Get-UIAWindow -ProcessName mmc | `
	Get-UIAMenuItem -Name File | `
	Invoke-UIAMenuItemClick).Current.Name

Not surprisingly, this code returned the name of the menu item selected. By default, all the cmdlets where it’s possible return the object of AutomationElement type.
However, you may change this behavior. If so, this code would return $true in success case and $false in case of an error, timeout, and cetera.
It’s needed rarely, because the if statement works well with $true/$false as well as the object/$null pair.
If you wish, you can change the code in the way:

Get-UIAWindow -ProcessName mmc | `
	Get-UIAMenuItem -Name File | `
	Invoke-UIAMenuItemClick -PassThru:$false;

Homework: experiment with return values. Try cmdlets one by one, which values they return with and without -PassThru.

(MS) UIAutomation: exporting from a grid


Task: export data from the data grid to a text file. As an example, use the Registry editor.

Task #2: provide a field for learning the module.

Requirements: just do it. Navigate through the Registry, find the values and export them to a file.

Solution: run the following code to get to the node:

Get-UIAWindow -Name 'Registry Editor' | `
	Get-UIATreeItem -Name HKEY_LOCAL_MACHINE | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name SOFTWARE | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name Microsoft | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name Windows | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name CurrentVersion | `
	Set-UIAFocus;

After the node is active, we’ll export the values:

	Get-UIADataGrid | `
		ConvertFrom-UIADataGrid | `
		Out-File "$($Env:TEMP)\export.txt";

All the values are already in the file.

ConvertFrom- cmdlets provide standard capabilities as do standard Convert cmdlets from Microsoft. For instance, you can pipeline to the Select-String cmdlet if you need check that a particular value(s) is in the grid.

To find out what was exported to the file, run the following:

Get-Content -Path "$($Env:TEMP)\export.txt" | `
	ConvertFrom-Csv;

Homework: try to export datagrid data from another key in the Registry editor or from the Services snap-in.

(MS) UIAutomation: navigating through a TreeView


Task: open the Registry editor, navigate to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion and select three values including Default.

Task #2: provide a field for learning the module.

Requirements: just do it. Go through the Registry tree. When the node you are searching for is found, step on it and work with values at the right.

Solution: run the following code:

Get-UIAWindow -Name 'Registry Editor' | `
	Get-UIATreeItem -Name HKEY_LOCAL_MACHINE | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name SOFTWARE | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name Microsoft | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name Windows | `
	Invoke-UIATreeItemExpand | `
	Get-UIATreeItem -Name CurrentVersion | `
	Set-UIAFocus;

	Get-UIADataGrid | `
		Invoke-UIADataItemSelectItem -ItemName `
			DevicePath,MediaPath,'(Default)',SM_GamesName

Note: usually a tree node does not support a click. Click may be used in specific nodes like those having a check box, for example. In this code we activated the CurrentVersion node by setting the focus on it.

Note: Invoke-UIADataItemSelectItem is a typical pattern cmdlet. They are often called Invoke- (MS guidelines say that synchronous operation must be invoked, whilst asynchronous should be verbed as Start-), though they are also may be members of Get- and Set- groups.
To form names for cmdlets is not an easy task! The same problem with the noun part: my rules tell me that the type of control in the name is on the top of usability. As well as the name of pattern.
On the other hand, how it is possible to concatenate such a construct:
Invoke-UIADataItemSelectionItem ?
Therefore, SelectionItemPattern is represented as SelectItem cmdlet. Understandable? I hope.

Patterns that are called Get- and Set- are usually paired.
Get-UIATextBoxText
Set-UIATextBoxText
Which alternatives can be proposed here? Invoke-UIATextBoxTextGet and Invoke-UIATextBoxTextSet? This was my first decision. ­čÖé

Homework: navigate to a node you like and work with the grid at right.

(MS) UIAutomation: working with a context menu


Task: select a service in the Services MMC snap-in (Windows XP). For the service selected, call its context menu and start the service. After that, stop the service through the context menu.

Task #2: provide a field for learning the module.

Requirements: just do it. The test should be repeatable.

Solution: run the following code:

Get-UIAWindow -Name 'Services' | `
	Get-UIADataGrid | `
	Get-UIADataItem -Name 'Alerter' | `
	Invoke-UIAControlContextMenu | `
	Get-UIAMenuItem -Name 'Start' | `
	Invoke-UIAMenuItemClick;

In the code snippet above, we get the window by name, get the grid (it does no matter, the Standard view is selected or the Extended one. However, this code uses a Win32 click (any cmdlet without a control type in the name may be a Win32-based cmdlet), which is sent to a geometrical center of the control), select a data item (the row) and perform a Win32 right-click. The click returns the window object (context menu is an independent window in the application process), where the last two cmdlets recognize and activate the menu item we’ve been tasked to click.
It’s a must for a tester to use after this code something with Get-Service or WMI to check that the service is started and so on.
After the test marked as Passed, the following code helps us to stop the service:

Get-UIAWindow -Name 'Services' | `
	Get-UIADataGrid | `
	Get-UIADataItem -Name 'Alerter' | `
	Invoke-UIAControlContextMenu | `
	Get-UIAMenuItem -Name 'Stop' | `
	Invoke-UIAMenuItemClick;

As a Homework, please open the Properties window of a service you chose.

%d bloggers like this: