New to Telerik Test StudioStart a free 30-day trial

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);

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). Reference to System.Drawing.dll have to be added to the project as well.

The below example 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.Common.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
    }
}

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));

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. A reference to UIAutomationClient.dll has to be added to the project and a using to System.Windows.Automation namespace would be required in the code. 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>
     /// This property is set when a dialog errors out and needs to abort.
     /// </summary>
     string ErrorText { get; set; }

     /// <summary>
     /// Gets/Sets the number of times this dialog has been handled.
     /// </summary>
     int HandleCount { get; set; }
 
     /// <summary>
     /// Gets/Sets a dialog handler delegate that will be used instead of
     /// the Handle() function.
     /// </summary>
     DialogHandlerDelegate HandlerDelegate { set; get;}

     /// <summary>
     /// Gets/Sets the time to before handling of the dialog starts.
     /// </summary>
     int InitializationTime { get; set; }

     /// <summary>
     /// Gets/Sets a dialog delegate that will be used if handling dialog will be skipped.
     /// </summary>
     Func<bool> SkipHandling { 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>
     /// 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();

     /// <summary>
     /// Detect whether this UI element completes the awaited conditions.
     /// For situations where window handles do not or need not apply.
     /// </summary>
	 bool MatchesUIAutomationElement(AutomationElement element);
}

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