Monthly Archives: March, 2012

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.

Advertisements

Daily automation: walking through the Start menu


Task: click the Computer item in the Start menu.

Requirements: use UIAutomation to demonstrate the technique.

Solution: although the solution is simple, it may be difficult to find out. The current version of UIAutomationSpy is slightly outdated and not yet recommends using the Get-UIADesktop cmdlet. Okay, this time we’ll do it manually, having in mind that a newer version of UIAutomationSpy is promised.

Here is the solution. At first, we open the Start menu by clicking the Start button. After that, we are seeking for a window that is the underlying level which the menu is placed upon. Finally, we get a list item, called of course Computer and send a Win32 click to there.

This sample is not ready to globalization.

ipmo [path]\UIAutomation.dll;

# click the Start button and open the Start menu
Get-UIADesktop | Get-UIAButton -Name Start | Invoke-UIAButtonClick; 
# Navigating through the Start menu and clicking the list item of our interest
Get-UIADesktop | Get-UIAcontrol -Class 'DV2ControlHost' -Name 'Start menu' | Get-UIAPane -Class 'DesktopSpecialFolders' | Get-UIAListItem -Name 'Computer' | Invoke-UIAControlClick;

After the code is processed by PowerShell, the Computer folder is open.

Daily automation: show me the desktop


How to perform Win+D or Win+M with confidence? I mean, without using unreliable SendKeys and with return value. Nothing unusual, as there is the ‘Show desktop’ button.

Task: click on the ‘Show desktop’ button programmatically.

Requirements: use UIAutomation module to minimize all the windows without an exception.

Solution: there would be suggested a traditional way:

ipmo [path]\UIAutomation.dll;

Get-UIADesktop | Get-UIAButton -Name 'Show desktop' | Invoke-UIAButtonClick;

Nope, this does not work even if we are  running the PowerShell console window in the Minimized window state.

How can we fix the issue? Let’s use a Win32 click:

ipmo [path]\UIAutomation.dll;

Get-UIADesktop | Get-UIAButton -Name 'Show desktop' | Invoke-UIAControlClick;

This code works as expected, from a minimized console, from a normal console, from everywhere.

Daily automation: open an application from the TaskBar


It’s easily to activate a window that is in the Normal or Maximized window state. However, what to do if a window is minimized? There’s no problem if it’s seen in the Windows TaskBar.

Task: click the window out of Windows TaskBar.

Requirements: use UIAutomation to demostrate the technique.

Solution: below is the piece of code that does the same the user does when one needs to return the window to a visible state. Apart with Alt+Tab and Alt+Shift+Tab, there is the simple click on the application’s rectangle in TaskBar.:

ipmo [path]\UIAutomation.dll;

# use the desktop element to get the button in TaskBar
# desktop AutomationElement is nothing else but
# [System.Windows.Automation.AutomationElement]::RootElement
Get-UIADesktop | Get-UIAButton -Name 'Windows Media Player' | Invoke-UIAButtonClick;

After the code is processed by PowerShell, the window of your choice appears on the screen.

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…

(MS) UIAutomation: putting text into a control


Task: demonstrate how to write in text into a text box field.

Requirements: use UI Automation pattern or Win32.

Solution: the typical code is as follows:

Get-UIAWindow -Name $formTitle | `
 Get-UIAEdit -AutomationId UsernameBox | `
 Set-UIAEditText -Text "text";

Despite the name, the Set-UIAEditText cmdlet uses ValuePattern. This is because that Set-UIAEditText as well as any Set-UIA[ControlType]Text cmdlet is an alias of the Invoke-UIAValuePatternSet cmdlet.
the same story with the Set-UIATextBoxText cmdlet, which is the alias for Set-UIAEditText.
Not every time controls that are supposed to support ValuePattern really support it. This may depend on the developer’s code or on a control’s state. For example, a combo box supports ValuePattern if it has a field to write text in.

As promised, accessing such controls programmatically should raise the ModifiedChanged event.

Sometimes, the ValuePattern can be inaccessible. Due to many reasons, it happens, though rarely. Under these circumstances, you may use the Set-UIAControlText cmdlet, the pure Win32 text setter.

Get-UIAWindow -Name $formTitle | `
 Get-UIAEdit -AutomationId UsernameBox | `
 Set-UIAControlText -Text "text";

Notice, however, that it works slightly differently: it puts text before the text that is already in the text field. What means that you need first to clean it up, the control, before putting a new text in.

(MS) UIAutomation: more ways to get a window


There’s been posted a request for more accurate method to get a window or control. Actually, getting a window by process name or window title may be considered by many as totally unreliable.
The application under test may be a page in the browser (several pages and browser instances are not rare these days), an MDI child, a frame. Simply, several instances of a GUI application can be running at the same time.
All these reasons led to adding new ways of getting windows.

Task: demonstrate how to get the window you’ll be using in tests by its process Id, window handle or process object.

Requirements: provide the reader with ready-to-run examples.

Solution: along with Get-UIAWindows -p (ProcessName) and -n (Name), the version 0.6.7 introduces new parameters for the Get-UIAWindow cmdlet.

    • -ProcessId or -pid
Get-UIAWindow -pid (Get-Process -Name mmc).Id
    • -Process or -p or -InputObject
Get-UIAWindow -p (Get-Process -Name mmc)

Earlier, many should do the following in order to start a process and get its handle:

Start-Process C:\Windows\system32\mmc.exe -Wait:$false
Get-UIAWindow -pn mmc -Seconds 10

the code says to start a process and seek for its window for no more than ten seconds.
Now, we are definitely more sure about what process we are going to get. We simply pipeline it to a cmdlet:

Start-Process C:\Windows\System32\mmc.exe -PassThru | Get-UIAWindow -Seconds 10

The sample provided hooks the same window that we ran in it.

One more requested feature is to handle windows and control by its handle. Whence the handle can be taken?
One way is to get the property:

(Start-Process C:\Windows\System32\mmc.exe -PassThru | Get-UIAWindow -Seconds 10).Current.NativeWindowhandle
(Start-Process C:\Windows\System32\mmc.exe -PassThru | Get-UIAWindow -Seconds 10 | Get-UIATree).Current.NativeWindowhandle

the other is to pipeline the handle out from the control:

PS C:\Users\apetrov1> Start-Process C:\Windows\System32\mmc.exe -PassThru | Get-UIAWindow -Seconds 10 | Read-UIAControlNativeWindowHandle
Start-Process C:\Windows\System32\mmc.exe -PassThru | Get-UIAWindow -Seconds 10 | Get-UIATree | Read-UIAControlNativeWindowHandle

After you’ve got the handle, you are free to use it until it’s being disposed by the operating system:

Get-UIAControlFromHandle -Handle 67856 | Get-UIATreeItem -Name 'Console Root'

(MS) UIAutomation: what are profiles (modes) and how to deal with them? Part 1


Task: demonstrate how to change the module settings in a bunch.

Task #2: provide an explanation what settings are.

Requirements: describe profiles and describe individual settings.

Solution: the UIAutomation module has a range of settigns. You can easily print them by running the following cmdlet:

Show-UIAModuleSettings;

The output provides you with a number of variables, some tell you something by their names, some don’t. Below are these settings:

C:\Users\Administrator> Show-UIAModuleSettings

Timeout settings:
[UIAutomation.Preferences]::Timeout = 20000

Error collection settings:
[UIAutomation.Preferences]::MaximumErrorCount = 256

Common actions:
[UIAutomation.Preferences]::OnErrorAction =
[UIAutomation.Preferences]::OnSleepAction =
[UIAutomation.Preferences]::OnSuccessDelay =

Screenshot settings:
[UIAutomation.Preferences]::OnErrorScreenShot = False
[UIAutomation.Preferences]::ScreenShotFolder = C:\Users\Administrator\AppData\Local\Temp

Log settings:
[UIAutomation.Preferences]::Log = True
[UIAutomation.Preferences]::LogPath = C:\Users\Administrator\AppData\Local\Temp\UIAutomation.log

Debugging delays:
[UIAutomation.Preferences]::OnClickDelay = 0
[UIAutomation.Preferences]::OnErrorDelay = 500
[UIAutomation.Preferences]::OnSleepDelay = 0
[UIAutomation.Preferences]::OnSuccessDelay = 500

Transcript settings
[UIAutomation.Preferences]::TranscriptInterval = 200

Highlighter settings:
[UIAutomation.Preferences]::Highlight = True
[UIAutomation.Preferences]::HighlighterBorder = 3
[UIAutomation.Preferences]::HighlighterColor = Color [Red]
C:\Users\Administrator>

What is what here? First of all, there is the need to mention also profiles (modes. Now, there is no decision on how to call them better :)).

Out of the box, you have the Presentation profile being set:

[UIAutomation.Mode]::Profile = [UIAutomation.Modes]::Presentation

This is colorful and not very fast. This is the face of the module: somebody downloads the module, tries to work with and shows to somebody else. The first thing the module should do well is to be accepted by the public. Why? Without the consumers, how should it progress?
Therefore, the first stage of the module life-cycle is being in the hands of newcomers (to the module). A tester, an IT manager or their boss(es), even the tester does through the newcomer stage.
Here comes the presentation mode: highlighting, half a second’s delays on every actions. Just to recline in the chair and watch the anime on the screen. Let’s explain these four settings:
[UIAutomation.Preferences]::OnClickDelay = 0
[UIAutomation.Preferences]::OnErrorDelay = 500
[UIAutomation.Preferences]::OnSleepDelay = 0
[UIAutomation.Preferences]::OnSuccessDelay = 500
If the cmdlet finished successfully (returned a control or called a pattern), it sleep for five hundred milliseconds. The time the spectators can use for exhaling and moving eyes.
If the cmdlet fails, it waits for 500 milliseconds, giving you the chance to stop the presentation or to continue if it’s not critical.
ONClickDelay is used in Win32 click cmdlets like Invoke-UIAControlClick and Invoke-UIAControlContextMenu.
OnSleepDelay is used in specific cases as if your host is overloaded and there is no reason to try to get an AutomationElement without a delay.
When you are debugging the script, the Debug mode is much more useful. It sleep a second after the success and five seconds after a failure.
When you are leaving the office and the script will work unattended, set the Normal mode, where there are no delays at all.
Moreover, all the settings, delays and others, you are allowed to change manually.
Homework: try to play with profiles (modes). Change individual settings. Observe, what are results. Change modes over any individual settings were done. Try change them in any combination.

%d bloggers like this: