Tag Archives: InvokePattern

Daily automation: a few windows in parallel


At work, an interesting question was raised: is it possible to work with several windows in parallel if their processes are run under various users? Yes, it surely is.

Task: use UIAutomation to get windows of AUTs that are run under various users.

Requirements: demonstrate how to use the technique and how to determine which window might cause a problem.

Solution: the first example is simple and demonstrates how to handle several windows:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll
Start-Process calc;
Start-Process calc;
Start-Process calc;
Start-Process calc;
Get-UIAWindow -ProcessName calc | Get-UIAButton -Name 1 | Invoke-UIAButtonClick | Read-UIAControlName
Get-UIAWindow -ProcessName calc | Get-UIAMenuItem -n vi* | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -n scien* | Invoke-UIAMenuItemClick

The sample starts the foursome of calculators, gets them all, clicks the 1 button and changes application mode to the Scientific one.

There is no difficulty with windows run under several user accounts while your test process (i.e., powershell) is running with at least equal or higher privileges.

Now, we’ll start calc under two different user accounts (credentials are not provided to the public domain just for you not locking your accounts ;):

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
(Start-Process calc -Credential (Get-Credential) -PassThru).Id
(Start-Process calc -Credential (Get-Credential) -PassThru).Id
# Here, we are writing up numbers to a paper
Get-UIAWindow -ProcessId 5924,6076 | Get-UIAMenuItem -Name vi* | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name scien* | Invoke-UIAMenuItemClick

This works, but the sample is not friendly to use: you need to store process ids. Okay, below is a better one-liner:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;
@((Start-Process calc -Credential (Get-Credential) -PassThru).Id; (Start-Process calc -Credential (Get-Credential) -PassThru).Id) | %{ Get-UIAWindow -ProcessId $_ | Get-UIAMenuItem -Name vi* | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name stat* | Invoke-UIAMenuItemClick; }

Finally, how to learn which window failed? For example, by defining a counting variable that will increment every window and point to an element of the windows array.

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: 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: 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: recording user’s actions


Applications are not stones. They’re changing during the user’s session. About which sort of changes am I talking? There might be several sorts of them:

  • the application structure changed (a new control appeared or an existing’s gone)
  • a control’s property changed
  • an event invoked (user clicked a control, for the easiest example)
  • a new child window appeared
  • the main window is closed

Today we discuss the case  of a control’s adding occurrence.

Task: demonstrate how to initiate the structure changed via an application’s menu item and how the change can be recorded.

Requirements: use the UIAutomation to use an event handler.

Solution: we are going to write events we collected to a log file and, for our information, to a message box:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;</pre>
# start the process and atach event handlers to the window
Start-Process notepad -PassThru | `
 Get-UIAWindow | `
 Register-UIAStructureChangedEvent -ChildAdded `
 -EventAction `
 { # write to a file
 param($src, $e)
 # report everything
 "'$($src.Current.Name)' has gotten a child" >> "$env:Temp\sample_report.txt";
 if ($src.Current.Name.Length -eq 0) {
 "===================================" >> "$env:Temp\sample_report.txt";
 "Oh, this is what we are waiting for!" >> "$env:Temp\sample_report.txt";
 "AutomaitonId = $($src.Current.AutomaitonId)" >> "$env:Temp\sample_report.txt";
 "ControlType = $($src.Current.ControlType.ProgrammaticName)" >> "$env:Temp\sample_report.txt";
 "ClassName = $($src.Current.ClassName)" >> "$env:Temp\sample_report.txt";
 "-----------------------------------" >> "$env:Temp\sample_report.txt";
 }
 },
 { # display a message box
 param($src, $e)
 # report only what happened under the menu item hierarchy
 if ($src.Current.ControlType.ProgrammaticName -eq 'ControlType.StatusBar') {
 [System.Windows.Forms.MessageBox]::Show($src.Current.Name + "`t" + `
 $src.Current.AutomationId + "`r`n" + `
 $e + "`r`n" + `
 $src.Current.ControlType.ProgrammaticName);
 }
 };

# depending on was or wasn't the Status Bar shown on
# the status bar will or won't be shown
# and the event handlers we linked to the window will fire
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
<pre>

After the code is processed by PowerShell, the log file in our user’s TEMP folder contains the information we’ve collected.

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…

%d bloggers like this: