Monday, 11 May 2015

Creating .CAB files with Powershell


Syntax for creating a cab file
New-CabinetFile -Name MyCabinet.cab -File "File01.exe","File02.txt"
--This creates a new MyCabinet.cab file in the current directory and adds the File01.exe and File02.txt files to it, also from the current directory.
Syntax for extracting a cab file
Get-ChildItem C:\CabFile\ | New-CabinetFile -Name MyCabinet.cab -DestinationPath C:\Users\UserA\Documents
--This creates a new C:\Users\UserA\Documents\MyCabinet.cab file and adds all files within the C:\CabFile\ directory into it.
Code for the New-CabinetFile function:
function New-CabinetFile {
    [CmdletBinding()]
    Param(
        [Parameter(HelpMessage="Target .CAB file name.", Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("FilePath")]
        [string] $Name,
        [Parameter(HelpMessage="File(s) to add to the .CAB.", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("FullName")]
        [string[]] $File,
        [Parameter(HelpMessage="Default intput/output path.", Position=2, ValueFromPipelineByPropertyName=$true)]
        [AllowNull()]
        [string[]] $DestinationPath,
        [Parameter(HelpMessage="Do not overwrite any existing .cab file.")]
        [Switch] $NoClobber
        )
    Begin { 
        ## If $DestinationPath is blank, use the current directory by default
        if ($DestinationPath -eq $null) { $DestinationPath = (Get-Location).Path; }
        Write-Verbose "New-CabinetFile using default path '$DestinationPath'.";
        Write-Verbose "Creating target cabinet file '$(Join-Path $DestinationPath $Name)'.";
        ## Test the -NoClobber switch
        if ($NoClobber) {
            ## If file already exists then throw a terminating error
            if (Test-Path -Path (Join-Path $DestinationPath $Name)) { throw "Output file '$(Join-Path $DestinationPath $Name)' already exists."; }
        }
        ## Cab files require a directive file, see 'http://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax' for more info
        $ddf = ";*** MakeCAB Directive file`r`n";
        $ddf += ";`r`n";
        $ddf += ".OPTION EXPLICIT`r`n";
        $ddf += ".Set CabinetNameTemplate=$Name`r`n";
        $ddf += ".Set DiskDirectory1=$DestinationPath`r`n";
        $ddf += ".Set MaxDiskSize=0`r`n";
        $ddf += ".Set Cabinet=on`r`n";
        $ddf += ".Set Compress=on`r`n";
        ## Redirect the auto-generated Setup.rpt and Setup.inf files to the temp directory
        $ddf += ".Set RptFileName=$(Join-Path $ENV:TEMP "setup.rpt")`r`n";
        $ddf += ".Set InfFileName=$(Join-Path $ENV:TEMP "setup.inf")`r`n";

        ## If -Verbose, echo the directive file
        if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
            foreach ($ddfLine in $ddf -split [Environment]::NewLine) {
                Write-Verbose $ddfLine;
            }
        }
    }
    Process {
         ## Enumerate all the files add to the cabinet directive file
        foreach ($fileToAdd in $File) {
            ## Test whether the file is valid as given and is not a directory
            if (Test-Path $fileToAdd -PathType Leaf) {
                Write-Verbose """$fileToAdd""";
                $ddf += """$fileToAdd""`r`n";
            }
            ## If not, try joining the $File with the (default) $DestinationPath
            elseif (Test-Path (Join-Path $DestinationPath $fileToAdd) -PathType Leaf) {
                Write-Verbose """$(Join-Path $DestinationPath $fileToAdd)""";
                $ddf += """$(Join-Path $DestinationPath $fileToAdd)""`r`n";
            }
            else { Write-Warning "File '$fileToAdd' is an invalid file or container object and has been ignored."; }
        }       
    }
    End {
        $ddfFile = Join-Path $DestinationPath "$Name.ddf";
        $ddf | Out-File $ddfFile -Encoding ascii | Out-Null;
        Write-Verbose "Launching 'MakeCab /f ""$ddfFile""'.";
        $makeCab = Invoke-Expression "MakeCab /F ""$ddfFile""";
        ## If Verbose, echo the MakeCab response/output
        if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
            ## Recreate the output as Verbose output
            foreach ($line in $makeCab -split [environment]::NewLine) {
                if ($line.Contains("ERROR:")) { throw $line; }
                else { Write-Verbose $line; }
            }
        }
        ## Delete the temporary .ddf file
        Write-Verbose "Deleting the directive file '$ddfFile'.";
        Remove-Item $ddfFile;
        ## Return the newly created .CAB FileInfo object to the pipeline
        Get-Item (Join-Path $DestinationPath $Name);
    }
}

Wednesday, 6 May 2015

unexpected popups handling in CodedUI

A lot of times, while running a UI test, our test runs into an unexpected page\state, say an unexpected error dialog, or an pop-up window, which would make our test fail and if that happens, rather than having the test rerun from the start, all we want is for it to resume when the page is loaded.
I am taking the example of a winforms application with an alert window. The steps would be no different if you were trying the same on any other supported technology.
Suppose let me say upon clicking a button there was an unexpected pop-up appearing. This pop-up blocks my TestMethod and makes it fail as it will not be able to perform any action as per the TestMethod. In this case these are the following steps which are to be followed
  1. Set a retry count- Playback.PlaybackSettings.MaximumRetryCount, i.e. you can specifiy the number of times you want a failed action to be retried. This is not a mandatory argument, if no value is set, the default value will be 1.
  2. Add a retry handler for the failed step. This is nothing but the handler function which will get called in case of a failure. You can add\remove this handler for any step in the coded UI test method, or even in test\class initialize as a generic handler for all failures.
  3.                         Playback.PlaybackError += Playback_PlaybackError;
  4. The handler method signature is as shown below
      1. private void Playback_PlaybackError(object sender, PlaybackErrorEventArgs e)
                {
                    Console.WriteLine("Retrying .... ");
                      // By default, the exception will be thrown. Over here we are switching to retry mode.
                      e.Result = PlaybackErrorOptions.Retry;
                        // Just a simple enter to dismiss the Alert. If you are sure of any specific properties for
                        // a popup dialog or any other specific action you need to do, this is the place to 
                        // implement them.
                        Keyboard.SendKeys("{Enter}");
                    }
        1. Now simply setting the PlaybackErrorOptions to Retry will retry your failed step over and over until either the step passes or the MaximumRetryCount is hit. If you want to do any special handling, like say dismissing an alert, you can add the code for the same within the handler.
        2. TestMethod code looks like below
            TestMethod()
                    {
                        using (ApplicationUnderTest aut = ApplicationUnderTest.Launch("UnexpectedPopupAut.exe"))
                        {
                            #region Variable Declarations
                            #endregion
            // Important to set the MaximumRetryCount count for the retry handler to be invoked.
                            Playback.PlaybackSettings.MaximumRetryCount = 3;
                            // Add the error handler.
                            Playback.PlaybackError += Playback_PlaybackError;
            //Code of your TestMethod
                            Playback.PlaybackError -= Playback_PlaybackError;
          This is supported only for the following exceptions:-
          1. PlaybackFailureException
          2. UITestControlNotFoundException
          3. UITestControlNotAvailableException
          4. TechnologyNotSupportedException
          5. InvalidUITestExtensionPackageException
          6. DecodingFailedException
          7. FailedToPerformActionsOnBlockedControlException
          8. FailedToPerformActionsOnHiddenControlException
          9. UITestControlNotVisibleException
          10. ValidationFailedException
          11. FailedToLaunchApplicationException
          12. ActionNotSupportedOnDisabledControlExcept

        Thursday, 12 February 2015

        Installation and Configuration of Test Controller and Test Agent without TFS


        Prerequisities

        Test controllers and Test agents have the following software requirement:
        Operating System
        To install a test controller or a test agent, the computer must run one of the following operating systems:
        Controller:
        • Windows 8, Windows 8.1
        • Windows 7 Service Pack 1
        • Windows Server 2012, Windows Server 2012 R2
        • Windows Server 2008 Release 2, Service Pack 1
        Agent:
        1. Windows 8, Windows 8.1
        2. Windows 7 Service Pack 1
        3. Windows XP Service Pack 3
        4. Windows Server 2012, Windows Server 2012 R2
        5. Windows Server 2008 Release 2, Service Pack 1
        6. Windows Server 2003 Service Pack 1
        .NET Framework
              To install a test controller or test agent, the computer must run the .NET Framework 4.5.

        UAC

              Change the UAC settings in both the systems to "Never Notify"

        New Local User as Administrator
              On each computer where you will install a test controller or a test agent, create a local user account that is a member of the Administrators group. Login with the local user and use the same account and password on each machine.
        1. Note:- If you are not Creating the Local User and using the same default administrator you might face issue while configuring
        2. Use this user account for your test controllers when you install and configure them.
           Team is the Local user which has been added into the machines where Test Controller and Test Agent are installed. On filling the above details by clicking on "Apply Settings" you see a pop up with validations happening. There will be an Configuration warning as we are not using the lab manager. It can be ignored
        3. Right click on the computer and Select Manage. In the Computer Management window, navigate to System Tools -> Local Users and Groups -> Groups. Add this account(i.e. Team) to the TeamTestAgentService group on the test controller machine.
        4. Install and configure your test agents using this same account(i.e Here Team).


          Configure the Test Agent with the following details. To register the Test Controller with this Test Agent give the IP Address and Click Apply Settings.
        5. Once the Setting are applied you can see a "Test Agent Status" Window appearing as below

          If the Test Agent Status is "Online" Then you are ready with the Set up for remote executions

        Monday, 9 February 2015

        Record one application only in CodedUI Test


        Generally, we test a single application using Coded UI Test. By default, Coded UI Test though will record actions on all applications.  Thus we may get unwanted actions on other application in our recording.

        We can prevent this by adding the following configuration in CodedUITestBuilder.exe.config file
        <add key="IncludeProcess" value="%SystemRoot%\system32\calc.exe"/>

        Replace calc.exe with the full path to your application. With this configuration only actions on calc.exe (or the application that you added) will be recorded.

        When using IncludeProcess, actions on the Windows desktop are not recorded. If you want to include actions on the Windows desktop, add the following configuration.
            <add key="RecordOnDesktopProcess" value="true"/>


        Alternately, we can also selectively exclude applications from recording using the following configuration.
        <add key="ExcludeProcess" value="%SystemRoot%\system32\calc.exe"/>
        Replace calc.exe with the full path to the application you want to exclude from recording.

        NOTE: These settings are applicable for Recording only. We can still drag the cross hair onto any application, get its properties and add assertions on them.

        If you see that no actions are being recorded on a particular application, first check this config file to ensure that the application has been added in the ExcludeProcess section. Also verify the IncludeProcess  configuration. If a particular process has been added in IncludeProcess, then actions on your applications will not be recorded.

        It is possible (though not recommended) to add process ids to IncludeProcess & ExcludeProcess configurations.

        Usage of Cordinate based actions in CodedUI


        When you record actions & generate code in Coded UI Test, you get actions like
        Mouse.Click(uISearchButton, new Point(18, 15));

        Many confuse by the Point argument we pass to Mouse.Click and believe that we are doing a coordinate based action. The Point argument here is relative to the button itself. So test will not fail if the button moves around in the page.

        More importantly, you can completely remove the Point argument. The code could be written as
        Mouse.Click(uISearchButton);

        This will still work. If no Point argument is specified, Visual Studio UI Test Framework determines a clickable point and performs the click on that point.

        So why do we use coordinates?

        There are specific scenarios where these coordinates really come in handy.

        Consider a DropDownButton, which drops down when you click on the expander arrow. If you click on the button’s normal area, it is invoked. If you click on the expander, it shows the additional buttons and you can click on one of them. Since we record relative coordinates for the click action, we can playback the actions on the expander also. If we had not recorded coordinates and clicked on the first available clickable point in the button, this scenario would have failed.
        e.g:- Look at the screenshot below.





        Here I am clicking on the expander in Picture Button to bring up additional options. This scenario will only work if we record relative coordinates on the click action.

        Tuesday, 20 January 2015

        Why does application close after each test in Coded UI Test


        In Coded UI, a flag CloseOnPlaybackCleanup is added to ApplicationUnderTest class. 
        For cases where an application is launched during test run, this flag helps determine whether to close the application under test after test is over.  Default value for the flag was set to true (closes the application) as it is not advisable to re-use resources from other test cases. 
        This works fine for Visual Studio 2012 and later versions. Users will see  BrowserWindow / ApplicationUnderTest is getting closed after each test case if they don't have CloseOnPlaybackCleanup flag set to false. 
         If you want to reuse any application instance launched in another test case, you have to assign CloseOnPlaybackCleanup flag to false for ApplicationUnderTest / BrowserWindow object.
        Please refer to sample code as below. If you run all these three tests together, BrowserWindow will be launched only once, remaining other tests will use existing browser instance from the previous test. If you run each test individually, then each test case will close the browser at the end of the run.

        public class CodedUITest1
            {
                public CodedUITest1()
                {
                }

                [TestMethod]
                public void CodedUITestMethod1()
                {
                   LoadLocalHost();
                }

                [TestMethod]
                public void CodedUITestMethod2()
                {
                    LoadLocalHost();
                }

                [TestMethod]
                public void CodedUITestMethod3()
                {
                    LoadLocalHost();
                }


                static BrowserWindow browserWindowInstance = null;

                public void LoadLocalHost()
                {
                    if (browserWindowInstance == null)
                    {
                        browserWindowInstance = BrowserWindow.Launch(new System.Uri("http://google.com/"));
                        browserWindowInstance.CloseOnPlaybackCleanup = false;
                        browserWindowInstance.Maximized = !browserWindowInstance.Maximized;
                    }
                    else
                    {
                        browserWindowInstance.Maximized = !browserWindowInstance.Maximized;
                    }
                }
        }     

        The same principle is applied with running tests using Command Line. If you are running tests altogether, the Application Under test will remain open in between tests in case CloseOnPlaybackCleanup is set to false. Once the run is over, all application instances which were launched during the run are closed.

        Searching a UI Test Control with an invalid property


        What if we give an invalid property as the Search/Filter property

        For Web technology,
        • If an invalid SearchProperty is used to Find a UITestControl, it will throw UITestControlNotFoundException. 
        e.g:- If you searched for the search edit box in google.com using a InvalidSearchProperty,
        this.mUISearchEdit.SearchProperties["InvalidSearchProperty"] = "foo-bar";
        you would get the UITestControlNotFoundException

        • If an invalid FilterProperty is used to Find a UITestControl, it will be ignored.
        e.g:- If you searched for the search edit box in google.com using a InvalidFilterProperty,
        this.mUISearchEdit.FilterProperties["InvalidFilterProperty"] = "foo-bar";
        you would succeed in locating the edit box and performing operations performed on it.

        For MSAA & UIA technologies,
        • If an invalid SearchProperty is used to Find a UITestControl, it will throw an ArgumentException
        e.g:- If you searched for the button ‘6’ in the calculator using a InvalidSearchProperty
        this.mUIItem6Button.SearchProperties["InvalidSearchProperty"] = "foo-bar";
        you would get the following exception.
        System.ArgumentException: The property InvalidSearchProperty is not a valid search property.
        • FilterProperties are not supported. If you specify FilterProperties for a WinForms or WPF control,  you will get the following message.
        System.ArgumentException: Filter properties are not supported by the following technology: MSAA. To search for a control, you must remove the filter properties.
        NOTE also for all technologies,
        • If an invalid Property is used in GetProperty/SetProperty, it will throw a NotSupportedException.