Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestStack.White TreeNode.Click() and TreeNode.Select() for leaf node does not work #672

Open
jeffhuckins opened this issue Oct 6, 2022 · 1 comment

Comments

@jeffhuckins
Copy link

I have a WPF window containing a TreeView. I am able to automate traversing the tree and can successfully select or click (either one) nodes with children, but it doesn't work for leaf nodes.

@jeffhuckins
Copy link
Author

jeffhuckins commented Oct 7, 2022

Update: I've discovered an issue with TestStack.White for TreeNodes

First of all, the Tree.node() method has never worked for our testing. It was necessary to implement our own traversal code:

` private TreeNode FindNode(TreeNode node, string sVal, bool bExpandNode)
{
LogEntry.Debug(log, "Entering");
TreeNode result = null;

        foreach (TreeNode tmpNode in node.Nodes)
        {
            LogEntry.Debug(log, $"Found node \"{FfiTreeNode.Text(tmpNode)}\"");

            if (FfiTreeNode.Text(tmpNode).Contains(sVal))
            {
                LogEntry.Debug(log, $"Found target node \"{sVal}\"");
                result = tmpNode;

                if (bExpandNode)
                {
                    FfiTreeNode.Expand(result, bExpandNode);
                }

                FfiTreeNode.Select(result);
                break;
            }

            Thread.Sleep(500);
        }

        LogEntry.Debug(log, "Leaving");
        return result;
    }

    public TreeNode SelectAppearanceItem(params string[] path)
    {
        LogEntry.Debug(log, "Entering");
        Tree treeAppearance = window.Get<Tree>(SearchCriteria.ByControlType(ControlType.Tree).AndAutomationId("treeViewAppearance"));
        TreeNode resultNode = null;

        if (treeAppearance != null)
        {
            resultNode = treeAppearance.Nodes[0];
            LogEntry.Debug(log, $"First node = \"{FfiTreeNode.Text(resultNode)}\"");

            for (int i = 0; i < path.Length; i++)
            {
                resultNode = FindNode(resultNode, path[i], i < path.Length - 1);

                if (resultNode == null)
                {
                    LogEntry.Debug(log, $"Appearance Tree Item, {path[i]}, not found!");
                    break;
                }
            }
        }

        LogEntry.Debug(log, "Leaving");
        return resultNode;
    }

`

I also had to create a static wrapper class in order to wrap calls to TreeNode action methods in try/catch due to erroneous Exceptions being thrown:

`namespace FormFactor.WinCal.Utilities
{
///


/// Robust TreeNode
///

internal static class FfiTreeNode
{
private static readonly log4net.ILog log =
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Click a TreeNode
    /// </summary>
    /// <param name="node"></param>
    public static void Select(TreeNode node)
    {
        LogEntry.Debug(log, $"Entering - selecting \"{Text(node)}\"");
        try
        {
            Mouse.Instance.Location = node.ClickablePoint;
            Mouse.Instance.Click();
        }
        catch { }
        LogEntry.Debug(log, $"Leaving - selecting \"{Text(node)}\"");
    }

    /// <summary>
    /// The DataView treeview items have custom headers with images, so checking TreeNode.Text property doesn't work
    /// </summary>
    /// <param name="node"></param>
    public static string Text(TreeNode node)
    {
        return node.HelpText;
    }

    /// <summary>
    /// Expand a node, if desired
    /// </summary>
    /// <param name="node"></param>
    /// <param name="expand"></param>
    public static void Expand(TreeNode node, bool expand)
    {
        LogEntry.Debug(log, $"Entering - Expanding \"{Text(node)}\"");
        try
        {
            if (node.Nodes.Count > 0)
            {
                node.Expand();
            }
        }
        catch { }
        LogEntry.Debug(log, $"Leaving - Expanding \"{Text(node)}\"");
    }
}

/// <summary>
/// Robust Menu
/// </summary>
internal static class FfiMenu
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Click menu
    /// </summary>
    /// <param name="menu"></param>
    /// <param name="path"></param>
    public static void Click(MenuBar menu, params string[] path)
    {
        LogEntry.Debug(log, "Entering");
        try
        {
            menu.MenuItem(path).Click();
        }
        catch(Exception e) 
        {
            string menuItems = string.Empty;

            for (int i = 0; i < path.Length; i++)
            {
                menuItems += $"\"{path[i]}\"";

                if (i < path.Length - 1)
                {
                    menuItems += ",";
                }
            }

            LogEntry.Debug(log, $"Menu Exception {menuItems}: {e.Message}");
        }

        LogEntry.Debug(log, "Entering");
    }
}

/// <summary>
/// Robust UiItem
/// </summary>
internal static class FfiUiItem
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Catch erroneous exceptions
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public static bool Enabled(UIItem item)
    {
        bool isEnabled = false;

        try
        {
            isEnabled = item.Enabled;
        }
        catch { }

        return isEnabled;
    }

    /// <summary>
    /// Click a UIItem
    /// </summary>
    /// <param name="item"></param>
    public static void Click(UIItem item)
    {
        try
        {
            item.Click();
        }
        catch { }
    }
}

/// <summary>
/// A robust button that uses exception handling because TestStack.White button clicks often erroneously cause exceptions
/// </summary>
internal static class FfiButton
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Click() to catch erroneous exceptions
    /// </summary>
    public static void Click(Button button)
    {
        try
        {
            button.Click();
        }
        catch { }
    }
}

/// <summary>
/// Robust RadioButton
/// </summary>
internal static class FfiRadioButton
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Click() to catch erroneous exceptions
    /// </summary>
    public static void Select(RadioButton button)
    {
        try
        {
            button.Select();
        }
        catch { }
        LogEntry.Debug(log, $"Selected '{button.Id}'");
    }

    /// <summary>
    /// IsSelected catch erroneous exceptions
    /// </summary>
    /// <param name="button"></param>
    /// <returns></returns>
    public static bool IsSelected(RadioButton button)
    {
        bool isSelected = false;

        try
        {
            isSelected = button.IsSelected;
        }
        catch { }

        return isSelected;
    }
}

/// <summary>
/// Robust ListBox
/// </summary>
internal static class FfiListBox
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Select() to catch erroneous exceptions
    /// </summary>
    /// <param name="listBox"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static ListBox Select(ListBox listBox, string value)
    {
        try
        {
            listBox.Select(value);
        }
        catch { }

        LogEntry.Debug(log, $"Selected '{value}' in '{listBox.Id}'");
        return listBox;
    }

    /// <summary>
    /// Select by index
    /// </summary>
    /// <param name="listBox"></param>
    /// <param name="idx"></param>
    /// <returns></returns>
    public static ListBox Select(ListBox listBox, int idx)
    {
        try
        {
            listBox.Select(idx);
        }
        catch { }

        LogEntry.Debug(log, $"Selected '{idx}' in '{listBox.Id}'");
        return listBox;
    }

    /// <summary>
    /// Double-Click the selected item - ONE OF THE ABOVE Select() methods MUST BE CALLED BEFORE THIS
    /// </summary>
    /// <param name="listBox"></param>
    public static void DoubleClick(ListBox listBox)
    {
        try
        {
            listBox.SelectedItem.DoubleClick();
        }
        catch { }
    }
}

/// <summary>
/// Robust combo box to handle erroneous exceptions from Select()
/// </summary>
internal static class FfiComboBox
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Select() to catch erroneous exceptions
    /// </summary>
    /// <param name="combo"></param>
    /// <param name="value"></param>
    public static ComboBox Select(ComboBox combo, string value)
    {
        try
        {
            combo.Select(value);
        }
        catch { }

        LogEntry.Debug(log, $"Selected '{value}' in '{combo.Id}'");
        return combo;
    }
}

/// <summary>
/// Robust Tab
/// </summary>
internal static class FfiTab
{
    private static readonly log4net.ILog log =
        log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Select() to catch erroneous exceptions
    /// </summary>
    /// <param name="combo"></param>
    /// <param name="value"></param>
    public static Tab SelectTabPage(Tab tab, string value)
    {
        try
        {
            tab.SelectTabPage(value);
        }
        catch { }

        LogEntry.Debug(log, $"Selected '{value}' in '{tab.Id}'");
        return tab;
    }

    /// <summary>
    /// Select() to catch erroneous exceptions
    /// </summary>
    /// <param name="combo"></param>
    /// <param name="value"></param>
    public static Tab SelectTabPage(Tab tab, int value)
    {
        try
        {
            tab.SelectTabPage(value);
        }
        catch { }

        LogEntry.Debug(log, $"Selected '{value}' in '{tab.Id}'");
        return tab;
    }
}

/// <summary>
/// Robust CheckBox
/// </summary>
internal static class FfiCheckBox
{
    /// <summary>
    /// Check or uncheck
    /// </summary>
    /// <param name="checkBox"></param>
    /// <param name="bCheck"></param>
    public static void SetCheck(CheckBox checkBox, bool bCheck)
    {
        try
        {
            if (bCheck)
            {
                Check(checkBox);
            }
            else
            {
                UnCheck(checkBox);
            }
        }
        catch { }
    }

    /// <summary>
    /// Check the checkbox
    /// </summary>
    /// <param name="checkBox"></param>
    public static void Check(CheckBox checkBox)
    {
        try
        {
            checkBox.Checked = true;
        }
        catch { }
    }

    /// <summary>
    /// UnCheck the checktox
    /// </summary>
    /// <param name="checkBox"></param>
    public static void UnCheck(CheckBox checkBox)
    {
        try
        {
            checkBox.Checked = false;
        }
        catch { }
    }
}

}
`

Finally, TreeNode.Click() and TreeNode.Select() do not work to completely traverse a Tree:

The only method that PARTIALLY works is:
Mouse.Instance.Location = node.ClickablePoint; Mouse.Instance.Click();
However, I discovered that this method doesn't work to click ALL child nodes of a node because TestStack.White clicks outside of the TreeNode header except for the child node that is widest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant