Creating Custom Dialog Handlers

So far we've addressed the common dialogs that browsers popup and how the built-in support can be used to handle them. So what do we do if we have a different dialog that we need to handle? Telerik Testing Framework provides a GenericDialog class (which does all the work for you of implementing a custom dialog handler), a BaseDialog class (which does most of the work of implementing a custom dialog handler), and the IDialog interface for when you need to roll your own custom dialog handler from scratch. Once implemented you can add your custom dialog handler to the DialogMonitor and have all your other dialogs handled just like the rest of the built-in dialogs.

Using the GenericDialog Class

Using the GenericDialog class you can create your own custom dialog handler that can handle most any simple standard Win32 dialog. Here's an example of how to implement a handler for Internet Explorers Security Warning dialog:

 

C#

GenericDialog SecurityWarningDialog = new GenericDialog(ActiveBrowser, "Security Warning", false, 1);  // Click on the Yes button

Manager.DialogMonitor.AddDialog(SecurityWarningDialog);

 

 

Visual Basic

Dim SecurityWarningDialog As GenericDialog = New GenericDialog(Me.ActiveBrowser, "Security Warning", False, 1)  ' Click on the Yes button

SecurityWarningDialog GenericDialog = GenericDialog(.ActiveBrowser, , , 1) 

Manager.DialogMonitor.AddDialog(SecurityWarningDialog)

 

Using the BaseDialog Class

By using the BaseDialog class as your base class to derive your custom dialog handler you only need to override the IsDialogActive() and Handle() functions. You may also provide your own constructor to validate the button type that will dismiss the dialog and/or accept a Desktop object (which you will need if you need to call Mouse.Click.or Keyboard.SendString). The following is a complete custom dialog handler that handles the "Security Alert" dialog displayed by Internet Explorer:

 

C#

using System;

 

using ArtOfTest.WebAii.Core;

using ArtOfTest.WebAii.Win32;

using ArtOfTest.WebAii.Win32.Dialogs;

 

namespace WebTesting

{

    public class SecurityAlertDialog : BaseDialog

    {

        #region Members

        /// <summary>

        /// The desktop object used to click dialog buttons.

        /// </summary>

        private Desktop _desktopObject;

        #endregion

 

        #region Private Constants

        /// <summary>

        /// The title (caption) of the dialog we want handled.

        /// </summary>

        private const string DIALOG_TITLE = "Security Alert";

        #endregion

 

        #region Constructor

        /// <summary>

        /// Create the dialog handler instance by passing it the parent browser and the

        /// button to click on to dismiss the dialog.

        /// </summary>

        /// <param name="parentBrowser">The parent browser.</param>

        /// <param name="dismissButton">The button to click to dismiss the dialog.</param>

        /// <param name="desktop">The desktop object to use for Mouse.Click calls.</param>

        public SecurityAlertDialog(Browser parentBrowser,

            DialogButton dismissButton, Desktop desktop)

            : base(parentBrowser, dismissButton)

        {

            if (dismissButton != DialogButton.YES && dismissButton != DialogButton.NO

                && dismissButton != DialogButton.CLOSE)

            {

                throw new

                    ArgumentException("Security dialog can only have dismiss button of types : YES, NO or CLOSE.");

            }

            _desktopObject = desktop;

        }

        #endregion

 

        #region Base Dialog Implementation

        /// <summary>

        /// Check whether the dialog is present or not. This function is

        /// called by the dialogmonitor object

        /// </summary>

        /// <param name="dialogs">This is a list of dialogs passed in

        /// by the DialogMonitor.</param>

        /// <returns>True/False whether this dialog is present.</returns>

        public override bool IsDialogActive(ArtOfTest.WebAii.Win32.WindowCollection dialogs)

        {

            return this.IsDialogActiveByTitle(dialogs, DIALOG_TITLE);

        }

 

        /// <summary>

        /// This is called by the DialogMonitor whenever IsDialogActive returns true.

        /// </summary>

        /// <returns>True/False whether the dialog was successfully handled.</returns>

        public override void Handle()

        {

            // If you are sharing this implementation with other

            // developers, this allows them to override this method

            // by setting the handler delegate. So if the

            // delegate is null, perform the built in handling logic

            // otherwise call the custom handling logic.

            if (this.HandlerDelegate != null)

            {

                this.HandlerDelegate(this);

            }

            else

            {

                try

                {

                    Window yesButton = WindowManager.FindWindowRecursively(this.Window.Handle, "&Yes", false, 0);

                    Window noButton = WindowManager.FindWindowRecursively(this.Window.Handle, "&No", false, 0);

                    Window okButton = WindowManager.FindWindowRecursively(this.Window.Handle, "OK", false, 0);

 

                    switch (this.DismissButton)

                    {

                        case DialogButton.CLOSE:

                            this.Window.Close();

                            break;

 

                        case DialogButton.OK:

                            _desktopObject.Mouse.Click(MouseClickType.LeftClick, okButton.Rectangle);

                            break;

 

                        case DialogButton.YES:

                            _desktopObject.Mouse.Click(MouseClickType.LeftClick, yesButton.Rectangle);

                            break;

 

                        case DialogButton.NO:

                            _desktopObject.Mouse.Click(MouseClickType.LeftClick, noButton.Rectangle);

                            break;

                    }

 

                    // Make sure the dialog is knocked down.

                    this.Window.WaitForVisibility(false, 500);

                }

                catch

                {

                    // Do any custom handling and return error.

                }

            }

        }

        #endregion

    }

}

 

Visual Basic

Imports System

Imports Microsoft.VisualStudio.TestTools.UnitTesting

 

Imports ArtOfTest.WebAii.Core

Imports ArtOfTest.WebAii.Win32

Imports ArtOfTest.WebAii.Win32.Dialogs

Imports ArtOfTest.WebAii.TestTemplates

 

Public Class SecurityAlertDialog

    Inherits BaseDialog

 

#Region "Members"

    ' <summary>

    ' The desktop object used to click dialog buttons.

    ' </summary>

    Private _desktopObject As Desktop

#End Region

 

#Region "Private Constants"

    ' <summary>

    ' The title (caption) of the dialog we want handled.

    ' </summary>

    Private Const DIALOG_TITLE As String = "Security Alert"

#End Region

 

#Region "Constructor"

    ' <summary>

    ' Create the dialog handler instance by passing it the parent browser and the

    ' button to click on to dismiss the dialog.

    ' </summary>

    ' <param name="parentBrowser">The parent browser.</param>

    ' <param name="dismissButton">The button to click to dismiss the dialog.</param>

    ' <param name="desktop">The desktop object to use for Mouse.Click calls.</param>

    Public Sub New(ByVal parentBrowser As ArtOfTest.WebAii.Core.Browser, _

      ByVal dismissButton As DialogButton, ByVal desktop As Desktop)

 

        MyBase.New(parentBrowser, dismissButton)

        If dismissButton <> DialogButton.YES And dismissButton <> DialogButton.NO _

          And dismissButton <> DialogButton.CLOSE Then

            Throw New ArgumentException("Security dialog can only have dismiss button of types : YES, NO or CLOSE.")

        End If

        _desktopObject = desktop

 

    End Sub

#End Region

 

#Region "Base Dialog Implementation"

 

    ' <summary>

    ' Check whether the dialog is present or not. This function is

    ' called by the dialogmonitor object

    ' </summary>

    ' <param name="dialogs">This is a list of dialogs passed in

    ' by the DialogMonitor.</param>

    ' <returns>True/False whether this dialog is present.</returns>

    Public Overrides Function IsDialogActive(ByVal dialogs As ArtOfTest.WebAii.Win32.WindowCollection) As Boolean

        Return IsDialogActiveByTitle(dialogs, DIALOG_TITLE)

    End Function

 

    ' <summary>

    ' This is called by the DialogMonitor whenever IsDialogActive returns true.

    ' </summary>

    ' <returns>True/False whether the dialog was successfully handled.</returns>

    Public Overrides Sub Handle()

        ' If you are sharing this implementation with other

        ' developers, this allows them to override this method

        ' by setting the handler delegate. So if the

        ' delegate is null, perform the built in handling logic

        ' otherwise call the custom handling logic.

        If Not IsNothing(Me.HandlerDelegate) Then

            Me.HandlerDelegate.Invoke(Me)

        Else

            Try

                Dim yesButton As Window = WindowManager.FindWindowRecursively(Me.Window.Handle, "&Yes", False, 0)

                Dim noButton As Window = WindowManager.FindWindowRecursively(Me.Window.Handle, "&No", False, 0)

                Dim okButton As Window = WindowManager.FindWindowRecursively(Me.Window.Handle, "OK", False, 0)

 

                Select Case Me.DismissButton

                    Case DialogButton.CLOSE

                        Me.Window.Close()

 

                    Case DialogButton.OK

                        Me._desktopObject.Mouse.Click(MouseClickType.LeftClick, okButton.Rectangle)

 

                    Case DialogButton.YES

                        Me._desktopObject.Mouse.Click(MouseClickType.LeftClick, yesButton.Rectangle)

 

                    Case DialogButton.NO

                        Me._desktopObject.Mouse.Click(MouseClickType.LeftClick, noButton.Rectangle)

 

                End Select

 

                ' Make sure the dialog is knocked down.

                Me.Window.WaitForVisibility(False, 500)

            Catch

                ' Do any custom handling and return error.

            End Try

 

        End If

 

    End Sub

#End Region

 

End Class

 

Once you have implemented your new custom dialog handler it requires just one line of code to add it to the DialogMonitor:

 

C#

Manager.DialogMonitor.AddDialog(new SecurityAlertDialog(ActiveBrowser, DialogButton.YES, Manager.Desktop));

 

Visual Basic

Manager.DialogMonitor.AddDialog(New SecurityAlertDialog(Me.ActiveBrowser, DialogButton.YES, Me.Manager.Desktop))

Implementing a Custom Dialog Handler with IDialog

When the GenericDialog and the BaseDialog classes don't provide the functionality you need, you can roll your own complete custom dialog handling by implementing the IDialog interface. An example of when this is necessary is when creating handlers for most FireFox dialogs. See How to handle FireFox dialogs for an example of a FireFox dialog handler implemented using the IDialog interface. The IDialog interface has the following methods and properties that you must implement:

 

C#

/// <summary>

/// Interface to implement for dialogs to be monitored and handled by the DialogMonitor object.

/// </summary>

public interface IDialog

{

     /// <summary>

     /// The dialogs current state. This property is Managed by the dialog

     /// monitor. Implementors should simply provide a private field to

     /// store this value for get/set operations.

     /// </summary>

     DialogCurrentState CurrentState { get; set; }

 

     /// <summary>

     /// Gets/Sets the number of times this dialog has been handled.

     /// </summary>

     int HandleCount { get; set; }

 

     /// <summary>

     /// The Window object that represents this dialog.

     /// IsDialogActive() should set this property if it is returning true.

     /// </summary>

     Window Window { get; }

 

     /// <summary>

     /// Gets/Sets a dialog handler delegate that will be used instead of

     /// the Handle() function.

     /// </summary>

     DialogHandlerDelegate HandlerDelegate { set; get;}

 

     /// <summary>

     /// Whether the dialog is active or not.

     /// </summary>

     /// <param name="dialogs">The list of dialogs present on the desktop.</param>

     /// <returns>True/False whether the dialog is active/present.</returns>

     bool IsDialogActive(WindowCollection dialogs);

 

     /// <summary>

     /// If a HandlerDelegate is set, this function should call the delegate,

     /// otherwise handle the dialog itself.

     /// </summary>

     void Handle();

}

 

Visual Basic

Public Interface IDialog

    ' <summary>

    ' The dialogs current state. This property is Managed by the dialog

    ' monitor. Implementors should simply provide a private field to

    ' store this value for get/set operations.

    ' </summary>

    Property CurrentState() As DialogCurrentState

 

    ' <summary>

    ' Gets/Sets the number of times this dialog has been handled.

    ' </summary>

    Property HandleCount() As Integer

 

    ' <summary>

    ' The Window object that represents this dialog.

    ' IsDialogActive() should set this property if it is returning true.

    ' </summary>

    ReadOnly Property Window() As ArtOfTest.WebAii.Win32.Window

 

    ' <summary>

    ' Gets/Sets a dialog handler delegate that will be used instead of

    ' the Handle() function.

    ' </summary>

    Property HandlerDelegate() As ArtOfTest.WebAii.Win32.Dialogs.DialogHandlerDelegate

 

    ' <summary>

    ' Whether the dialog is active or not.

    ' </summary>

    ' <param name="dialogs">The list of dialogs present on the desktop.</param>

    ' <returns>True/False whether the dialog is active/present.</returns>

    Function IsDialogActive(ByVal dialogs As ArtOfTest.WebAii.Win32.WindowCollection) As Boolean

 

    ' <summary>

    ' If a HandlerDelegate is set, this function should call the delegate,

    ' otherwise handle the dialog itself.

    ' </summary>

    Sub Handle()

 

End Interface

 

After implementing this interface and creating an instance of your class in your test code, you can add the instance to the DialogMonitor to begin handling of your special dialog. See Handling FireFox dialogs for an example of implementing the IDialog interface. The interface is pretty straight forward but here is how the DialogMonitor uses it:
  • Periodically (depending on the monitoring interval), the DialogMonitor will call the IsDialogActive() passing all active dialogs currently on the desktop. [Note: The DialogMonitor passes only the dialog windows, not all windows. Meaning windows with class name = #32770]
  • The implementation of IsDialogActive then should determine if the dialog it was built to handle is active or not. If so, it should set an internal property to store that window and return true. The instance should be accessible using the Window property.
  • If the DialogMonitor() detects true to any call to IsDialogActive(), it will automatically call the Handle() method.
  • The Handle() method should then perform the custom handling for that dialog and knock it down. The method should return 'true' if it was successful in knocking down the dialog else 'false'.